chore: migrate to AGPL-3.0-only

This commit is contained in:
weishu
2026-01-04 20:45:15 +08:00
parent 34cfe49f87
commit 37c6bc83d7
20 changed files with 1298 additions and 463 deletions
+2 -2
View File
@@ -4,7 +4,7 @@ import { jwtVerify } from 'jose'
import { z } from 'zod'
import type { Store } from '../store'
import { configuration } from '../configuration'
import { safeCompareStrings } from '../utils/crypto'
import { constantTimeEquals } from '../utils/crypto'
import { parseAccessToken } from '../utils/accessToken'
import { registerCliHandlers } from './handlers/cli'
import { registerTerminalHandlers } from './handlers/terminal'
@@ -98,7 +98,7 @@ export function createSocketServer(deps: SocketServerDeps): {
const auth = socket.handshake.auth as Record<string, unknown> | undefined
const token = typeof auth?.token === 'string' ? auth.token : null
const parsedToken = token ? parseAccessToken(token) : null
if (!parsedToken || !safeCompareStrings(parsedToken.baseToken, configuration.cliApiToken)) {
if (!parsedToken || !constantTimeEquals(parsedToken.baseToken, configuration.cliApiToken)) {
return next(new Error('Invalid token'))
}
socket.data.namespace = parsedToken.namespace
+14 -9
View File
@@ -1,14 +1,19 @@
import { timingSafeEqual } from 'node:crypto'
export function safeCompareStrings(a: string | null | undefined, b: string | null | undefined): boolean {
if (a == null || b == null) {
return false
}
const bufA = Buffer.from(a, 'utf8')
const bufB = Buffer.from(b, 'utf8')
try {
return timingSafeEqual(bufA, bufB)
} catch {
export function constantTimeEquals(a: string | null | undefined, b: string | null | undefined): boolean {
if (typeof a !== 'string' || typeof b !== 'string') {
return false
}
const bufferA = Buffer.from(a, 'utf8')
const bufferB = Buffer.from(b, 'utf8')
const maxLength = Math.max(bufferA.length, bufferB.length)
const paddedA = Buffer.alloc(maxLength)
const paddedB = Buffer.alloc(maxLength)
bufferA.copy(paddedA)
bufferB.copy(paddedB)
const matches = timingSafeEqual(paddedA, paddedB)
return matches && bufferA.length === bufferB.length
}
+2 -2
View File
@@ -2,7 +2,7 @@ import { Hono } from 'hono'
import { SignJWT } from 'jose'
import { z } from 'zod'
import { configuration } from '../../configuration'
import { safeCompareStrings } from '../../utils/crypto'
import { constantTimeEquals } from '../../utils/crypto'
import { parseAccessToken } from '../../utils/accessToken'
import { validateTelegramInitData } from '../telegramInitData'
import { getOrCreateOwnerId } from '../ownerId'
@@ -38,7 +38,7 @@ export function createAuthRoutes(jwtSecret: Uint8Array, store: Store): Hono<WebA
// Access Token authentication (CLI_API_TOKEN)
if ('accessToken' in parsed.data) {
const parsedToken = parseAccessToken(parsed.data.accessToken)
if (!parsedToken || !safeCompareStrings(parsedToken.baseToken, configuration.cliApiToken)) {
if (!parsedToken || !constantTimeEquals(parsedToken.baseToken, configuration.cliApiToken)) {
return c.json({ error: 'Invalid access token' }, 401)
}
userId = await getOrCreateOwnerId()
+2 -2
View File
@@ -2,7 +2,7 @@ import { Hono } from 'hono'
import { SignJWT } from 'jose'
import { z } from 'zod'
import { configuration } from '../../configuration'
import { safeCompareStrings } from '../../utils/crypto'
import { constantTimeEquals } from '../../utils/crypto'
import { parseAccessToken } from '../../utils/accessToken'
import { validateTelegramInitData } from '../telegramInitData'
import { getOrCreateOwnerId } from '../ownerId'
@@ -25,7 +25,7 @@ export function createBindRoutes(jwtSecret: Uint8Array, store: Store): Hono<WebA
}
const parsedToken = parseAccessToken(parsed.data.accessToken)
if (!parsedToken || !safeCompareStrings(parsedToken.baseToken, configuration.cliApiToken)) {
if (!parsedToken || !constantTimeEquals(parsedToken.baseToken, configuration.cliApiToken)) {
return c.json({ error: 'Invalid access token' }, 401)
}
const namespace = parsedToken.namespace
+2 -2
View File
@@ -1,7 +1,7 @@
import { Hono } from 'hono'
import { z } from 'zod'
import { configuration } from '../../configuration'
import { safeCompareStrings } from '../../utils/crypto'
import { constantTimeEquals } from '../../utils/crypto'
import { parseAccessToken } from '../../utils/accessToken'
import type { Machine, Session, SyncEngine } from '../../sync/syncEngine'
@@ -76,7 +76,7 @@ export function createCliRoutes(getSyncEngine: () => SyncEngine | null): Hono<Cl
const token = parsed.data.replace(/^Bearer\s+/i, '')
const parsedToken = parseAccessToken(token)
if (!parsedToken || !safeCompareStrings(parsedToken.baseToken, configuration.cliApiToken)) {
if (!parsedToken || !constantTimeEquals(parsedToken.baseToken, configuration.cliApiToken)) {
return c.json({ error: 'Invalid token' }, 401)
}