Spaces:
Sleeping
Sleeping
| import express from 'express'; | |
| import { OAuth2Client } from 'google-auth-library'; | |
| import https from 'node:https'; | |
| import path from 'node:path'; | |
| import { fileURLToPath } from 'node:url'; | |
| const __filename = fileURLToPath(import.meta.url); | |
| const __dirname = path.dirname(__filename); | |
| const appRoot = path.resolve(__dirname, '..'); | |
| const distDir = path.join(appRoot, 'dist'); | |
| const PORT = Number(process.env.PORT || 7860); | |
| const HOST = process.env.HOST || '0.0.0.0'; | |
| const GOOGLE_CLIENT_ID = process.env.GOOGLE_CLIENT_ID || process.env.VITE_GOOGLE_CLIENT_ID || ''; | |
| const DRIVE_FOLDER_ID = | |
| process.env.DRIVE_FOLDER_ID || | |
| process.env.VITE_DRIVE_FOLDER_ID || | |
| '1xK0ZNYBpVeYBKca48xxKEFpGWy9bbRaw'; | |
| const ALLOWED_DOMAIN = 'baby-helmet.com'; | |
| const DRIVE_API_BASE = 'https://www.googleapis.com/drive/v3'; | |
| const ORIGINAL_OBJ_PATTERN = /^ldsm_fit_original_\d{5}_[^_]+_\d{8}\.obj$/i; | |
| const oauthClient = new OAuth2Client(GOOGLE_CLIENT_ID); | |
| const app = express(); | |
| function jsonError(res, status, message) { | |
| return res.status(status).json({ error: message }); | |
| } | |
| function getBearerToken(req) { | |
| const header = req.get('authorization') || ''; | |
| const match = header.match(/^Bearer\s+(.+)$/i); | |
| return match?.[1] || ''; | |
| } | |
| async function verifyBabyHelmetUser(req, res, next) { | |
| if (!GOOGLE_CLIENT_ID) { | |
| return jsonError(res, 500, 'GOOGLE_CLIENT_ID is not configured.'); | |
| } | |
| const idToken = req.get('x-google-id-token') || ''; | |
| if (!idToken) { | |
| return jsonError(res, 401, 'Google ID token is required.'); | |
| } | |
| try { | |
| const ticket = await oauthClient.verifyIdToken({ | |
| idToken, | |
| audience: GOOGLE_CLIENT_ID, | |
| }); | |
| const payload = ticket.getPayload(); | |
| if (!payload) { | |
| return jsonError(res, 403, 'Invalid Google ID token.'); | |
| } | |
| const email = String(payload.email || '').toLowerCase(); | |
| const hostedDomain = String(payload.hd || '').toLowerCase(); | |
| if (payload.aud !== GOOGLE_CLIENT_ID) { | |
| return jsonError(res, 403, 'Invalid token audience.'); | |
| } | |
| if (hostedDomain !== ALLOWED_DOMAIN) { | |
| return jsonError(res, 403, 'Google Workspace domain is not allowed.'); | |
| } | |
| if (payload.email_verified !== true) { | |
| return jsonError(res, 403, 'Google email is not verified.'); | |
| } | |
| if (!email.endsWith(`@${ALLOWED_DOMAIN}`)) { | |
| return jsonError(res, 403, 'Email domain is not allowed.'); | |
| } | |
| req.verifiedUser = { email }; | |
| return next(); | |
| } catch { | |
| return jsonError(res, 403, 'Google ID token verification failed.'); | |
| } | |
| } | |
| function requireDriveAccessToken(req, res, next) { | |
| const accessToken = getBearerToken(req); | |
| if (!accessToken) { | |
| return jsonError(res, 401, 'Google Drive access token is required.'); | |
| } | |
| req.driveAccessToken = accessToken; | |
| return next(); | |
| } | |
| async function driveFetch(pathname, accessToken, options = {}) { | |
| const url = new URL(`${DRIVE_API_BASE}${pathname}`); | |
| const headers = { | |
| Authorization: `Bearer ${accessToken}`, | |
| ...(options.headers || {}), | |
| }; | |
| return new Promise((resolve, reject) => { | |
| const req = https.request( | |
| url, | |
| { | |
| method: options.method || 'GET', | |
| headers, | |
| timeout: 20000, | |
| }, | |
| (res) => { | |
| const chunks = []; | |
| res.on('data', (chunk) => { | |
| chunks.push(chunk); | |
| }); | |
| res.on('end', () => { | |
| clearTimeout(timeoutId); | |
| const body = Buffer.concat(chunks).toString('utf8'); | |
| const status = res.statusCode || 0; | |
| const response = { | |
| ok: status >= 200 && status < 300, | |
| status, | |
| json: async () => JSON.parse(body), | |
| text: async () => body, | |
| }; | |
| if (!response.ok) { | |
| reject(new Error(`Google Drive API error ${response.status}: ${body}`)); | |
| return; | |
| } | |
| resolve(response); | |
| }); | |
| }, | |
| ); | |
| const timeoutId = setTimeout(() => { | |
| req.destroy(new Error('Google Drive API request timed out.')); | |
| }, 20000); | |
| req.on('error', (error) => { | |
| clearTimeout(timeoutId); | |
| reject(error); | |
| }); | |
| req.end(); | |
| }); | |
| } | |
| async function listFolderObjFiles(accessToken) { | |
| const files = []; | |
| let pageToken = ''; | |
| do { | |
| const params = new URLSearchParams({ | |
| q: `'${DRIVE_FOLDER_ID}' in parents and trashed = false and name contains 'ldsm_fit_original_'`, | |
| fields: 'files(id,name,size,modifiedTime,mimeType),nextPageToken', | |
| orderBy: 'name_natural', | |
| pageSize: '1000', | |
| supportsAllDrives: 'true', | |
| includeItemsFromAllDrives: 'true', | |
| }); | |
| if (pageToken) { | |
| params.set('pageToken', pageToken); | |
| } | |
| const response = await driveFetch(`/files?${params}`, accessToken); | |
| const data = await response.json(); | |
| files.push(...(data.files || [])); | |
| pageToken = data.nextPageToken || ''; | |
| } while (pageToken); | |
| return files.filter((file) => ORIGINAL_OBJ_PATTERN.test(file.name)); | |
| } | |
| async function getObjMetadata(fileId, accessToken) { | |
| const params = new URLSearchParams({ | |
| fields: 'id,name,size,modifiedTime,mimeType,parents', | |
| supportsAllDrives: 'true', | |
| }); | |
| const response = await driveFetch(`/files/${encodeURIComponent(fileId)}?${params}`, accessToken); | |
| return response.json(); | |
| } | |
| function isObjInFixedFolder(file) { | |
| const parents = Array.isArray(file.parents) ? file.parents : []; | |
| return ORIGINAL_OBJ_PATTERN.test(file.name || '') && parents.includes(DRIVE_FOLDER_ID); | |
| } | |
| app.get('/env.js', (_req, res) => { | |
| res.type('application/javascript').send( | |
| `window.__APP_CONFIG__ = ${JSON.stringify({ | |
| googleClientId: GOOGLE_CLIENT_ID, | |
| driveFolderId: DRIVE_FOLDER_ID, | |
| })};`, | |
| ); | |
| }); | |
| app.get('/api/health', (_req, res) => { | |
| res.json({ ok: true }); | |
| }); | |
| app.get('/api/files', verifyBabyHelmetUser, requireDriveAccessToken, async (req, res) => { | |
| try { | |
| const files = await listFolderObjFiles(req.driveAccessToken); | |
| res.json({ files }); | |
| } catch (error) { | |
| jsonError(res, 502, error.message || 'Failed to list Drive files.'); | |
| } | |
| }); | |
| app.get('/api/files/:id', verifyBabyHelmetUser, requireDriveAccessToken, async (req, res) => { | |
| try { | |
| const file = await getObjMetadata(req.params.id, req.driveAccessToken); | |
| if (!isObjInFixedFolder(file)) { | |
| return jsonError(res, 403, 'Requested file is not an OBJ in the configured folder.'); | |
| } | |
| const response = await driveFetch( | |
| `/files/${encodeURIComponent(file.id)}?alt=media&supportsAllDrives=true`, | |
| req.driveAccessToken, | |
| ); | |
| const text = await response.text(); | |
| res.type('text/plain; charset=utf-8').send(text); | |
| } catch (error) { | |
| jsonError(res, 502, error.message || 'Failed to download OBJ file.'); | |
| } | |
| }); | |
| app.use(express.static(distDir)); | |
| app.use((_req, res) => { | |
| res.sendFile(path.join(distDir, 'index.html')); | |
| }); | |
| app.listen(PORT, HOST, () => { | |
| console.log(`OBJ Drive Viewer listening on ${HOST}:${PORT}`); | |
| }); | |