fix(extension): generate the API token with a CSPRNG and restrict the discovery file
The bearer token came from Math.random(), which is predictable. Use crypto.randomBytes and write piagentui-port.json (which stores the token) with mode 0600.
This commit is contained in:
1 parent
e8927ebf78
commit
ceca5bf301
1 file changed
+9
-3
@@ -3,7 +3,7 @@ import { WebSocketServer, WebSocket } from 'ws'
|
||||
import * as http from 'node:http'
|
||||
import * as fs from 'node:fs'
|
||||
import * as path from 'node:path'
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { randomBytes, randomUUID } from 'node:crypto'
|
||||
import {
|
||||
validateBearerToken,
|
||||
preventPathTraversal,
|
||||
@@ -721,7 +721,8 @@ export default function (pi: ExtensionAPI) {
|
||||
}
|
||||
|
||||
function generateBearerToken(): string {
|
||||
return Array.from({ length: 4 }, () => Math.random().toString(36).substring(2)).join('-')
|
||||
// CSPRNG: the token is the only credential guarding the local API.
|
||||
return randomBytes(24).toString('base64url')
|
||||
}
|
||||
|
||||
const settingsStore = createPiAgentUiSettingsStore(resolvePiAgentUiSettingsPaths())
|
||||
@@ -2065,7 +2066,12 @@ export default function (pi: ExtensionAPI) {
|
||||
if (!fs.existsSync(piAgentDir)) {
|
||||
fs.mkdirSync(piAgentDir, { recursive: true })
|
||||
}
|
||||
fs.writeFileSync(discoveryPath, JSON.stringify({ port: localPort, token: localToken }, null, 2), 'utf8')
|
||||
// The file holds the API token: keep it readable by the owner only (mode is ignored on Windows).
|
||||
fs.writeFileSync(discoveryPath, JSON.stringify({ port: localPort, token: localToken }, null, 2), {
|
||||
encoding: 'utf8',
|
||||
mode: 0o600,
|
||||
})
|
||||
fs.chmodSync(discoveryPath, 0o600)
|
||||
console.log(`[PiAgentUi] Wrote connection info to: ${discoveryPath}`)
|
||||
} catch (err) {
|
||||
console.error('[PiAgentUi] Failed to write discovery file:', err)
|
||||
|
||||
Reference in new issue
Block a user