From bebd6a61ebe2bc2783ef4769b8404e5f27ba5854 Mon Sep 17 00:00:00 2001 From: syui Date: Wed, 11 Jun 2025 13:20:01 +0900 Subject: [PATCH] fix xxxcard log --- README.md | 4 +- aicard-web-oauth/.env | 4 + aicard-web-oauth/.env.development | 4 + aicard-web-oauth/.env.production | 4 + aicard-web-oauth/package.json | 1 + aicard-web-oauth/public/client-metadata.json | 14 ++-- aicard-web-oauth/src/App.tsx | 46 +++++++++--- .../src/services/atproto-oauth.ts | 12 +-- aicard-web-oauth/src/utils/oauth-keys.ts | 41 +++------- aicard-web-oauth/vite.config.ts | 75 +++++++++++++------ run.zsh | 9 ++- 11 files changed, 133 insertions(+), 81 deletions(-) create mode 100644 aicard-web-oauth/.env create mode 100644 aicard-web-oauth/.env.development create mode 100644 aicard-web-oauth/.env.production diff --git a/README.md b/README.md index 52fc704..182cd1b 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ AI-powered static blog generator with ATProto integration, part of the ai.ai eco | Command | Description | |---------|-------------| -| `./run.zsh c` | Enable Cloudflare tunnel (xxxcard.syui.ai) for OAuth | -| `./run.zsh o` | Start OAuth web server (port:4173 = xxxcard.syui.ai) | +| `./run.zsh c` | Enable Cloudflare tunnel (log.syui.ai) for OAuth | +| `./run.zsh o` | Start OAuth web server (port:4173 = log.syui.ai) | | `./run.zsh co` | Start comment system (ATProto stream monitor) | ## 🏗️ Architecture (Pure Rust + HTML + JS) diff --git a/aicard-web-oauth/.env b/aicard-web-oauth/.env new file mode 100644 index 0000000..dbfe579 --- /dev/null +++ b/aicard-web-oauth/.env @@ -0,0 +1,4 @@ +# Default environment variables (fallback) +VITE_APP_HOST=https://log.syui.ai +VITE_OAUTH_CLIENT_ID=https://log.syui.ai/client-metadata.json +VITE_OAUTH_REDIRECT_URI=https://log.syui.ai/oauth/callback \ No newline at end of file diff --git a/aicard-web-oauth/.env.development b/aicard-web-oauth/.env.development new file mode 100644 index 0000000..97c77d4 --- /dev/null +++ b/aicard-web-oauth/.env.development @@ -0,0 +1,4 @@ +# Development environment variables +VITE_APP_HOST=http://localhost:4173 +VITE_OAUTH_CLIENT_ID=http://localhost:4173/client-metadata.json +VITE_OAUTH_REDIRECT_URI=http://localhost:4173/oauth/callback \ No newline at end of file diff --git a/aicard-web-oauth/.env.production b/aicard-web-oauth/.env.production new file mode 100644 index 0000000..15692f4 --- /dev/null +++ b/aicard-web-oauth/.env.production @@ -0,0 +1,4 @@ +# Production environment variables +VITE_APP_HOST=https://log.syui.ai +VITE_OAUTH_CLIENT_ID=https://log.syui.ai/client-metadata.json +VITE_OAUTH_REDIRECT_URI=https://log.syui.ai/oauth/callback \ No newline at end of file diff --git a/aicard-web-oauth/package.json b/aicard-web-oauth/package.json index 4cff1b2..f6430cc 100644 --- a/aicard-web-oauth/package.json +++ b/aicard-web-oauth/package.json @@ -6,6 +6,7 @@ "dev": "vite --mode development", "build": "vite build --mode production", "build:dev": "vite build --mode development", + "build:local": "VITE_APP_HOST=http://localhost:4173 vite build --mode development", "preview": "vite preview" }, "dependencies": { diff --git a/aicard-web-oauth/public/client-metadata.json b/aicard-web-oauth/public/client-metadata.json index 4d79d3d..8af8db1 100644 --- a/aicard-web-oauth/public/client-metadata.json +++ b/aicard-web-oauth/public/client-metadata.json @@ -1,13 +1,13 @@ { - "client_id": "https://xxxcard.syui.ai/client-metadata.json", + "client_id": "https://log.syui.ai/client-metadata.json", "client_name": "ai.card", - "client_uri": "https://xxxcard.syui.ai", - "logo_uri": "https://xxxcard.syui.ai/favicon.ico", - "tos_uri": "https://xxxcard.syui.ai/terms", - "policy_uri": "https://xxxcard.syui.ai/privacy", + "client_uri": "https://log.syui.ai", + "logo_uri": "https://log.syui.ai/favicon.ico", + "tos_uri": "https://log.syui.ai/terms", + "policy_uri": "https://log.syui.ai/privacy", "redirect_uris": [ - "https://xxxcard.syui.ai/oauth/callback", - "https://xxxcard.syui.ai/" + "https://log.syui.ai/oauth/callback", + "https://log.syui.ai/" ], "response_types": [ "code" diff --git a/aicard-web-oauth/src/App.tsx b/aicard-web-oauth/src/App.tsx index 3d105c2..8a37b5c 100644 --- a/aicard-web-oauth/src/App.tsx +++ b/aicard-web-oauth/src/App.tsx @@ -99,9 +99,9 @@ function App() { return false; }; - // キャッシュがなければ、ATProtoから取得 + // キャッシュがなければ、ATProtoから取得(認証状態に関係なく) if (!loadCachedComments()) { - loadAllComments(window.location.href); + loadAllComments(); // URLフィルタリングを無効にして全コメント表示 } // Handle popstate events for mock OAuth flow @@ -142,7 +142,8 @@ function App() { setUser(userProfile); // Load all comments for display (this will be the default view) - loadAllComments(window.location.href); + // Temporarily disable URL filtering to see all comments + loadAllComments(); // Load user list records if admin if (userProfile.did === 'did:plc:uqzpqmrjnptsxezjx4xuh2mn') { @@ -161,7 +162,8 @@ function App() { setUser(verifiedUser); // Load all comments for display (this will be the default view) - loadAllComments(window.location.href); + // Temporarily disable URL filtering to see all comments + loadAllComments(); // Load user list records if admin if (verifiedUser.did === 'did:plc:uqzpqmrjnptsxezjx4xuh2mn') { @@ -169,6 +171,9 @@ function App() { } } setIsLoading(false); + + // 認証状態に関係なく、コメントを読み込む + loadAllComments(); }; checkAuth(); @@ -265,17 +270,20 @@ function App() { try { // 管理者のユーザーリストを取得 (ai.syui.log.user collection) const adminDid = 'did:plc:uqzpqmrjnptsxezjx4xuh2mn'; // syui.ai + console.log('Fetching user list from admin DID:', adminDid); const response = await fetch(`https://bsky.social/xrpc/com.atproto.repo.listRecords?repo=${encodeURIComponent(adminDid)}&collection=ai.syui.log.user&limit=100`); if (!response.ok) { - console.warn('Failed to fetch user list from admin, using default users'); + console.warn('Failed to fetch user list from admin, using default users. Status:', response.status); return getDefaultUsers(); } const data = await response.json(); const userRecords = data.records || []; + console.log('User records found:', userRecords.length); if (userRecords.length === 0) { + console.log('No user records found, using default users'); return getDefaultUsers(); } @@ -349,20 +357,33 @@ function App() { }; const getDefaultUsers = () => { - return [ + const defaultUsers = [ // bsky.social - 実際のDIDを使用 { did: 'did:plc:uqzpqmrjnptsxezjx4xuh2mn', handle: 'syui.ai', pds: 'https://bsky.social' }, - // 他のユーザーは実際のDIDが不明なので、実在するユーザーのみ含める ]; + + // 現在ログインしているユーザーも追加(重複チェック) + if (user && user.did && user.handle && !defaultUsers.find(u => u.did === user.did)) { + defaultUsers.push({ + did: user.did, + handle: user.handle, + pds: user.handle.endsWith('.syu.is') ? 'https://syu.is' : 'https://bsky.social' + }); + } + + console.log('Default users list (including current user):', defaultUsers); + return defaultUsers; }; // 新しい関数: 全ユーザーからコメントを収集 const loadAllComments = async (pageUrl?: string) => { try { console.log('Loading comments from all users...'); + console.log('Page URL filter:', pageUrl); // ユーザーリストを動的に取得 const knownUsers = await loadUsersFromRecord(); + console.log('Known users for comment fetching:', knownUsers); const allComments = []; @@ -388,7 +409,8 @@ function App() { ? userComments.filter(record => record.value.url === pageUrl) : userComments; - console.log(`After URL filtering: ${filteredComments.length} comments from ${user.handle}`); + console.log(`After URL filtering (${pageUrl}): ${filteredComments.length} comments from ${user.handle}`); + console.log('All comments from this user:', userComments.map(r => ({ url: r.value.url, text: r.value.text }))); allComments.push(...filteredComments); } catch (err) { console.warn(`Failed to load comments from ${user.handle}:`, err); @@ -859,14 +881,16 @@ function App() { diff --git a/aicard-web-oauth/src/services/atproto-oauth.ts b/aicard-web-oauth/src/services/atproto-oauth.ts index 0a1235e..e4851bf 100644 --- a/aicard-web-oauth/src/services/atproto-oauth.ts +++ b/aicard-web-oauth/src/services/atproto-oauth.ts @@ -188,13 +188,15 @@ class AtprotoOAuthService { } private getClientId(): string { - const origin = window.location.origin; - - // For production (xxxcard.syui.ai), use the actual URL - if (origin.includes('xxxcard.syui.ai')) { - return `${origin}/client-metadata.json`; + // Use environment variable if available + const envClientId = import.meta.env.VITE_OAUTH_CLIENT_ID; + if (envClientId) { + console.log('Using client ID from environment:', envClientId); + return envClientId; } + const origin = window.location.origin; + // For localhost development, use undefined for loopback client // The BrowserOAuthClient will handle this automatically if (origin.includes('localhost') || origin.includes('127.0.0.1')) { diff --git a/aicard-web-oauth/src/utils/oauth-keys.ts b/aicard-web-oauth/src/utils/oauth-keys.ts index 85282d2..9be43d6 100644 --- a/aicard-web-oauth/src/utils/oauth-keys.ts +++ b/aicard-web-oauth/src/utils/oauth-keys.ts @@ -157,40 +157,19 @@ export class OAuthKeyManager { * Generate dynamic client metadata based on current URL */ export function generateClientMetadata(): any { - const origin = window.location.origin; - const clientId = `${origin}/client-metadata.json`; + // Use environment variables if available, fallback to current origin + const host = import.meta.env.VITE_APP_HOST || window.location.origin; + const clientId = import.meta.env.VITE_OAUTH_CLIENT_ID || `${host}/client-metadata.json`; + const redirectUri = import.meta.env.VITE_OAUTH_REDIRECT_URI || `${host}/oauth/callback`; - // Use static production metadata for xxxcard.syui.ai - if (origin === 'https://xxxcard.syui.ai') { - return { - client_id: 'https://xxxcard.syui.ai/client-metadata.json', - client_name: 'ai.card', - client_uri: 'https://xxxcard.syui.ai', - logo_uri: 'https://xxxcard.syui.ai/favicon.ico', - tos_uri: 'https://xxxcard.syui.ai/terms', - policy_uri: 'https://xxxcard.syui.ai/privacy', - redirect_uris: ['https://xxxcard.syui.ai/oauth/callback'], - response_types: ['code'], - grant_types: ['authorization_code', 'refresh_token'], - token_endpoint_auth_method: 'private_key_jwt', - token_endpoint_auth_signing_alg: 'ES256', - scope: 'atproto transition:generic', - subject_type: 'public', - application_type: 'web', - dpop_bound_access_tokens: true, - jwks_uri: 'https://xxxcard.syui.ai/.well-known/jwks.json' - }; - } - - // Dynamic metadata for development return { client_id: clientId, client_name: 'ai.card', - client_uri: origin, - logo_uri: `${origin}/favicon.ico`, - tos_uri: `${origin}/terms`, - policy_uri: `${origin}/privacy`, - redirect_uris: [`${origin}/oauth/callback`], + client_uri: host, + logo_uri: `${host}/favicon.ico`, + tos_uri: `${host}/terms`, + policy_uri: `${host}/privacy`, + redirect_uris: [redirectUri, host], response_types: ['code'], grant_types: ['authorization_code', 'refresh_token'], token_endpoint_auth_method: 'private_key_jwt', @@ -199,6 +178,6 @@ export function generateClientMetadata(): any { subject_type: 'public', application_type: 'web', dpop_bound_access_tokens: true, - jwks_uri: `${origin}/.well-known/jwks.json` + jwks_uri: `${host}/.well-known/jwks.json` }; } \ No newline at end of file diff --git a/aicard-web-oauth/vite.config.ts b/aicard-web-oauth/vite.config.ts index 0fb8cad..0707304 100644 --- a/aicard-web-oauth/vite.config.ts +++ b/aicard-web-oauth/vite.config.ts @@ -1,31 +1,58 @@ -import { defineConfig } from 'vite' +import { defineConfig, loadEnv } from 'vite' import react from '@vitejs/plugin-react' +import fs from 'fs' +import path from 'path' -export default defineConfig({ - plugins: [react()], - build: { - // Keep console.log in production for debugging - minify: 'esbuild', - }, - esbuild: { - drop: [], // Don't drop console.log - }, - server: { - port: 5173, - host: '127.0.0.1', - allowedHosts: ['localhost', '127.0.0.1', 'xxxcard.syui.ai'], - proxy: { - '/api': { - target: 'http://127.0.0.1:8000', - changeOrigin: true, - secure: false, +export default defineConfig(({ mode }) => { + // Load env file based on `mode` in the current working directory. + const env = loadEnv(mode, process.cwd(), '') + + return { + plugins: [ + react(), + // Custom plugin to replace variables in public files during build + { + name: 'replace-env-vars', + writeBundle() { + const host = env.VITE_APP_HOST || 'https://log.syui.ai' + const clientId = env.VITE_OAUTH_CLIENT_ID || `${host}/client-metadata.json` + const redirectUri = env.VITE_OAUTH_REDIRECT_URI || `${host}/oauth/callback` + + // Replace variables in client-metadata.json + const clientMetadataPath = path.resolve(__dirname, 'dist/client-metadata.json') + if (fs.existsSync(clientMetadataPath)) { + let content = fs.readFileSync(clientMetadataPath, 'utf-8') + content = content.replace(/https:\/\/log\.syui\.ai/g, host) + fs.writeFileSync(clientMetadataPath, content) + console.log(`Updated client-metadata.json with host: ${host}`) + } + } } + ], + build: { + // Keep console.log in production for debugging + minify: 'esbuild', }, - // Handle OAuth callback routing - historyApiFallback: { - rewrites: [ - { from: /^\/oauth\/callback/, to: '/index.html' } - ] + esbuild: { + drop: [], // Don't drop console.log + }, + server: { + port: 5173, + host: '127.0.0.1', + allowedHosts: ['localhost', '127.0.0.1', 'log.syui.ai'], + proxy: { + '/api': { + target: 'http://127.0.0.1:8000', + changeOrigin: true, + secure: false, + } + }, + // Handle OAuth callback routing + historyApiFallback: { + rewrites: [ + { from: /^\/oauth\/callback/, to: '/index.html' } + ] + } } } }) \ No newline at end of file diff --git a/run.zsh b/run.zsh index 580bff7..798da70 100755 --- a/run.zsh +++ b/run.zsh @@ -18,7 +18,8 @@ function _server() { function _server_public() { _env - cloudflared tunnel --config $d/aicard-web-oauth/cloudflared-config.yml run + #cloudflared tunnel --config $d/aicard-web-oauth/cloudflared-config.yml run + cloudflared tunnel --config $d/cloudflared-config.yml run } function _oauth_build() { @@ -29,6 +30,12 @@ function _oauth_build() { [ -s "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" ] && \. "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" # This loads nvm bash_completion nvm use 21 npm i + + # Build with production environment variables + export VITE_APP_HOST="https://log.syui.ai" + export VITE_OAUTH_CLIENT_ID="https://log.syui.ai/client-metadata.json" + export VITE_OAUTH_REDIRECT_URI="https://log.syui.ai/oauth/callback" + npm run build npm run preview }