From 5311241fe56da9d36419bb2260821907875dbea0 Mon Sep 17 00:00:00 2001 From: Ponshu Developer Date: Sat, 11 Apr 2026 00:16:52 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=E3=83=A9=E3=82=A4=E3=82=BB=E3=83=B3?= =?UTF-8?q?=E3=82=B9=E6=A4=9C=E8=A8=BC=E3=82=92VPS=E3=82=A8=E3=83=B3?= =?UTF-8?q?=E3=83=89=E3=83=9D=E3=82=A4=E3=83=B3=E3=83=88=E3=81=B8=E7=A7=BB?= =?UTF-8?q?=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - secrets.dart: posimaiBaseUrl を追加 (https://api.soar-enrich.com) - license_service.dart: 検証URLをproxyから /api/ponshu/license/validate へ変更 + LicenseStatus.trialExpired 参照バグを修正 + _cachedTrialInfo 残骸変数参照を削除 - proxy/server.js: /license/validate と /admin/license/revoke を削除 (ライセンス管理はPostgreSQL + VPS server.js が担当) Co-Authored-By: Claude Sonnet 4.6 --- lib/secrets.dart | 6 +++ lib/services/license_service.dart | 5 +-- tools/proxy/server.js | 74 +------------------------------ 3 files changed, 9 insertions(+), 76 deletions(-) diff --git a/lib/secrets.dart b/lib/secrets.dart index a9891ce..033de05 100644 --- a/lib/secrets.dart +++ b/lib/secrets.dart @@ -72,5 +72,11 @@ class Secrets { return local.SecretsLocal.geminiApiKey; } + /// Posimai メインサーバーのベースURL(ライセンス検証に使用) + static const String posimaiBaseUrl = String.fromEnvironment( + 'POSIMAI_BASE_URL', + defaultValue: 'https://api.soar-enrich.com', + ); + // static const String driveClientId = String.fromEnvironment('DRIVE_CLIENT_ID', defaultValue: ''); } diff --git a/lib/services/license_service.dart b/lib/services/license_service.dart index c8eda33..1a0e34a 100644 --- a/lib/services/license_service.dart +++ b/lib/services/license_service.dart @@ -97,7 +97,6 @@ class LicenseService { await prefs.remove(_prefLicenseKey); await prefs.remove(_prefCachedStatus); await prefs.remove(_prefCachedAt); - _cachedTrialInfo = null; debugPrint('[License] Reset complete.'); } @@ -112,7 +111,7 @@ class LicenseService { try { final deviceId = await DeviceService.getDeviceId(); final response = await http.post( - Uri.parse('${Secrets.aiProxyBaseUrl}/license/validate'), + Uri.parse('${Secrets.posimaiBaseUrl}/api/ponshu/license/validate'), headers: {'Content-Type': 'application/json'}, body: jsonEncode({'license_key': key, 'device_id': deviceId}), ).timeout(const Duration(seconds: 15)); @@ -121,7 +120,7 @@ class LicenseService { if (data['valid'] == true) return LicenseStatus.pro; if ((data['error'] as String? ?? '').contains('無効化')) return LicenseStatus.revoked; - return LicenseStatus.trialExpired; + return LicenseStatus.free; } catch (e) { debugPrint('[License] Validation network error: $e'); diff --git a/tools/proxy/server.js b/tools/proxy/server.js index 586b8a8..51f68fc 100644 --- a/tools/proxy/server.js +++ b/tools/proxy/server.js @@ -78,7 +78,7 @@ function authMiddleware(req, res, next) { app.use(bodyParser.json({ limit: '10mb' })); app.use((req, res, next) => { - const publicPaths = ['/health', '/license/validate']; + const publicPaths = ['/health']; if (publicPaths.includes(req.path)) return next(); authMiddleware(req, res, next); }); @@ -182,78 +182,6 @@ app.post('/analyze', async (req, res) => { } }); -// 新規: ライセンス検証 (認証不要 — アプリが直接呼ぶ) -app.post('/license/validate', async (req, res) => { - const { license_key, device_id } = req.body; - - if (!license_key || !device_id) { - return res.status(400).json({ valid: false, error: 'Missing parameters' }); - } - - try { - const license = await redisClient.hGetAll(`license:${license_key}`); - - if (!license || Object.keys(license).length === 0) { - return res.json({ valid: false, error: 'ライセンスキーが見つかりません' }); - } - - if (license.status === 'revoked') { - return res.json({ valid: false, error: 'このライセンスは無効化されています。サポートにお問い合わせください。' }); - } - - // 初回アクティベート - if (!license.deviceId || license.deviceId === '') { - await redisClient.hSet(`license:${license_key}`, 'deviceId', device_id); - await redisClient.hSet(`license:${license_key}`, 'activatedAt', new Date().toISOString()); - - console.log(`[License] Activated: ${license_key} → Device: ${device_id.substring(0, 8)}...`); - return res.json({ valid: true, plan: license.plan, activated: true }); - } - - // 既存デバイスの照合 - if (license.deviceId !== device_id) { - console.log(`[License] Device mismatch: ${license_key}`); - return res.json({ - valid: false, - error: '別のデバイスで登録済みです。端末変更の場合はサポートまでご連絡ください。', - supportEmail: APP_SUPPORT_EMAIL, - }); - } - - return res.json({ valid: true, plan: license.plan }); - - } catch (err) { - console.error('[License] Validate error:', err); - res.status(500).json({ valid: false, error: 'サーバーエラーが発生しました' }); - } -}); - -// 管理用 — ライセンス失効 (認証必須) -app.post('/admin/license/revoke', async (req, res) => { - const { license_key } = req.body; - - if (!license_key) { - return res.status(400).json({ success: false, error: 'license_key required' }); - } - - try { - const exists = await redisClient.hExists(`license:${license_key}`, 'status'); - if (!exists) { - return res.json({ success: false, error: 'License not found' }); - } - - await redisClient.hSet(`license:${license_key}`, 'status', 'revoked'); - await redisClient.hSet(`license:${license_key}`, 'revokedAt', new Date().toISOString()); - - console.log(`[Admin] License revoked: ${license_key}`); - return res.json({ success: true, message: `License ${license_key} has been revoked` }); - - } catch (err) { - console.error('[Admin] Revoke error:', err); - res.status(500).json({ success: false, error: 'Server error' }); - } -}); - // ヘルスチェック app.get('/health', (req, res) => { res.send('OK');