@kraki/head 0.10.3 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/account-api.d.ts +35 -0
- package/dist/account-api.js +254 -0
- package/dist/account-api.js.map +1 -0
- package/dist/auth-backend.d.ts +92 -0
- package/dist/auth-backend.js +11 -0
- package/dist/auth-backend.js.map +1 -0
- package/dist/cli.js +254 -45
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/ip-geo.d.ts +22 -0
- package/dist/ip-geo.js +89 -0
- package/dist/ip-geo.js.map +1 -0
- package/dist/local-auth-backend.d.ts +109 -0
- package/dist/local-auth-backend.js +420 -0
- package/dist/local-auth-backend.js.map +1 -0
- package/dist/remote-auth-backend.d.ts +48 -0
- package/dist/remote-auth-backend.js +89 -0
- package/dist/remote-auth-backend.js.map +1 -0
- package/dist/server.d.ts +10 -0
- package/dist/server.js +147 -24
- package/dist/server.js.map +1 -1
- package/dist/storage.d.ts +53 -1
- package/dist/storage.js +248 -9
- package/dist/storage.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local auth backend — validates credentials using local auth providers and Storage.
|
|
3
|
+
* Used when head runs in standalone mode (no remote account service).
|
|
4
|
+
*/
|
|
5
|
+
import type { AuthMethod, DeviceInfo } from '@kraki/protocol';
|
|
6
|
+
import type { AuthBackend, AuthOutcome, ChallengeOutcome, AuthInfoConfig } from './auth-backend.js';
|
|
7
|
+
import type { AuthProvider } from './auth.js';
|
|
8
|
+
import type { Storage } from './storage.js';
|
|
9
|
+
import type { PushManager } from './push/index.js';
|
|
10
|
+
export interface LocalAuthBackendOptions {
|
|
11
|
+
storage: Storage;
|
|
12
|
+
authProviders: Map<string, AuthProvider>;
|
|
13
|
+
pairingEnabled?: boolean;
|
|
14
|
+
pairingTtl?: number;
|
|
15
|
+
pushManager?: PushManager;
|
|
16
|
+
/** This head's region (e.g., 'us', 'china'). If set, region checks are enforced. */
|
|
17
|
+
region?: string;
|
|
18
|
+
/** Map of region name → relay URL for wrong_region redirects. */
|
|
19
|
+
regionUrls?: Record<string, string>;
|
|
20
|
+
}
|
|
21
|
+
export interface RegionDirectoryEntry {
|
|
22
|
+
code: string;
|
|
23
|
+
relayUrl: string;
|
|
24
|
+
displayName?: string;
|
|
25
|
+
}
|
|
26
|
+
export type LoginResolveOutcome = {
|
|
27
|
+
ok: true;
|
|
28
|
+
registered: boolean;
|
|
29
|
+
needsRegionSelection: boolean;
|
|
30
|
+
user: {
|
|
31
|
+
id: string;
|
|
32
|
+
login: string;
|
|
33
|
+
provider: string;
|
|
34
|
+
email?: string;
|
|
35
|
+
preferences?: Record<string, unknown>;
|
|
36
|
+
region?: string;
|
|
37
|
+
};
|
|
38
|
+
region?: string;
|
|
39
|
+
relayUrl?: string;
|
|
40
|
+
suggestedRegion?: string;
|
|
41
|
+
regions: RegionDirectoryEntry[];
|
|
42
|
+
} | {
|
|
43
|
+
ok: false;
|
|
44
|
+
code: string;
|
|
45
|
+
message: string;
|
|
46
|
+
};
|
|
47
|
+
export type EdgeJoinOutcome = {
|
|
48
|
+
ok: true;
|
|
49
|
+
region: string;
|
|
50
|
+
relayUrl: string;
|
|
51
|
+
displayName?: string;
|
|
52
|
+
serviceKey: string;
|
|
53
|
+
} | {
|
|
54
|
+
ok: false;
|
|
55
|
+
code: string;
|
|
56
|
+
message: string;
|
|
57
|
+
};
|
|
58
|
+
export declare class LocalAuthBackend implements AuthBackend {
|
|
59
|
+
private storage;
|
|
60
|
+
private authProviders;
|
|
61
|
+
private pairingEnabled;
|
|
62
|
+
private pairingTtl;
|
|
63
|
+
private pushManager?;
|
|
64
|
+
private region?;
|
|
65
|
+
private regionUrls;
|
|
66
|
+
private pairingTokens;
|
|
67
|
+
constructor(options: LocalAuthBackendOptions);
|
|
68
|
+
authenticate(auth: AuthMethod, device: DeviceInfo, headRegion?: string): Promise<AuthOutcome>;
|
|
69
|
+
startChallenge(deviceId: string, _encryptionKey?: string, headRegion?: string): Promise<ChallengeOutcome>;
|
|
70
|
+
verifyChallenge(deviceId: string, nonce: string, signature: string, encryptionKey?: string, headRegion?: string): Promise<AuthOutcome>;
|
|
71
|
+
createPairingToken(userId: string): {
|
|
72
|
+
token: string;
|
|
73
|
+
expiresIn: number;
|
|
74
|
+
};
|
|
75
|
+
requestPairingToken(token: string, ip?: string): Promise<{
|
|
76
|
+
ok: true;
|
|
77
|
+
userId: string;
|
|
78
|
+
pairingToken: string;
|
|
79
|
+
expiresIn: number;
|
|
80
|
+
} | {
|
|
81
|
+
ok: false;
|
|
82
|
+
code: string;
|
|
83
|
+
message: string;
|
|
84
|
+
}>;
|
|
85
|
+
getAuthInfo(): AuthInfoConfig;
|
|
86
|
+
resolveLogin(auth: AuthMethod, preferredRegion?: string, clientIp?: string): Promise<LoginResolveOutcome>;
|
|
87
|
+
getRegions(): RegionDirectoryEntry[];
|
|
88
|
+
getRegionVersion(): number;
|
|
89
|
+
completeEdgeJoin(token: string, region: string, relayUrl: string, displayName?: string): EdgeJoinOutcome;
|
|
90
|
+
validateServiceKey(serviceKey: string): {
|
|
91
|
+
valid: boolean;
|
|
92
|
+
region?: string;
|
|
93
|
+
};
|
|
94
|
+
/** Sweep expired pairing tokens. Called periodically by HeadServer. */
|
|
95
|
+
sweepPairingTokens(): void;
|
|
96
|
+
private handlePairingAuth;
|
|
97
|
+
private completeAuth;
|
|
98
|
+
private checkRegion;
|
|
99
|
+
private resolveAuthUser;
|
|
100
|
+
private isAuthError;
|
|
101
|
+
private buildUserProfile;
|
|
102
|
+
private getRelayUrlForRegion;
|
|
103
|
+
private getProviderForMode;
|
|
104
|
+
private findGitHubProvider;
|
|
105
|
+
private getGitHubClientId;
|
|
106
|
+
private getVapidPublicKey;
|
|
107
|
+
private getDeviceSummaries;
|
|
108
|
+
private flushPending;
|
|
109
|
+
}
|
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local auth backend — validates credentials using local auth providers and Storage.
|
|
3
|
+
* Used when head runs in standalone mode (no remote account service).
|
|
4
|
+
*/
|
|
5
|
+
import { randomBytes, createVerify } from 'crypto';
|
|
6
|
+
import { v4 as uuid } from 'uuid';
|
|
7
|
+
import { GitHubAuthProvider } from './auth.js';
|
|
8
|
+
import { getLogger } from './logger.js';
|
|
9
|
+
import { suggestRegionForIp } from './ip-geo.js';
|
|
10
|
+
function importPublicKey(compactKey) {
|
|
11
|
+
const lines = compactKey.match(/.{1,64}/g) ?? [];
|
|
12
|
+
return `-----BEGIN PUBLIC KEY-----\n${lines.join('\n')}\n-----END PUBLIC KEY-----\n`;
|
|
13
|
+
}
|
|
14
|
+
function verifySignature(nonce, signature, publicKeyPem) {
|
|
15
|
+
const verify = createVerify('SHA256');
|
|
16
|
+
verify.update(nonce);
|
|
17
|
+
return verify.verify(publicKeyPem, signature, 'base64');
|
|
18
|
+
}
|
|
19
|
+
export class LocalAuthBackend {
|
|
20
|
+
storage;
|
|
21
|
+
authProviders;
|
|
22
|
+
pairingEnabled;
|
|
23
|
+
pairingTtl;
|
|
24
|
+
pushManager;
|
|
25
|
+
region;
|
|
26
|
+
regionUrls;
|
|
27
|
+
pairingTokens = new Map();
|
|
28
|
+
constructor(options) {
|
|
29
|
+
this.storage = options.storage;
|
|
30
|
+
this.authProviders = options.authProviders;
|
|
31
|
+
this.pairingEnabled = options.pairingEnabled ?? true;
|
|
32
|
+
this.pairingTtl = options.pairingTtl ?? 300;
|
|
33
|
+
this.pushManager = options.pushManager;
|
|
34
|
+
this.region = options.region;
|
|
35
|
+
this.regionUrls = options.regionUrls ?? {};
|
|
36
|
+
}
|
|
37
|
+
async authenticate(auth, device, headRegion) {
|
|
38
|
+
const logger = getLogger();
|
|
39
|
+
if (auth.method === 'pairing') {
|
|
40
|
+
return this.handlePairingAuth(auth.token, device, headRegion);
|
|
41
|
+
}
|
|
42
|
+
if (auth.method === 'challenge') {
|
|
43
|
+
return { ok: false, code: 'unknown_auth_method', message: 'Use startChallenge/verifyChallenge for challenge auth' };
|
|
44
|
+
}
|
|
45
|
+
const resolved = await this.resolveAuthUser(auth);
|
|
46
|
+
if (this.isAuthError(resolved)) {
|
|
47
|
+
logger.warn('Auth rejected', { method: auth.method, reason: resolved.message });
|
|
48
|
+
return resolved;
|
|
49
|
+
}
|
|
50
|
+
return this.completeAuth(resolved, device, auth.method, headRegion);
|
|
51
|
+
}
|
|
52
|
+
async startChallenge(deviceId, _encryptionKey, headRegion) {
|
|
53
|
+
const device = this.storage.getDevice(deviceId);
|
|
54
|
+
if (!device || !device.publicKey) {
|
|
55
|
+
return { ok: false, code: 'unknown_device', message: 'Unknown device' };
|
|
56
|
+
}
|
|
57
|
+
// Region check: look up the user for this device
|
|
58
|
+
const regionCheck = this.checkRegion(device.userId, headRegion);
|
|
59
|
+
if (regionCheck)
|
|
60
|
+
return regionCheck;
|
|
61
|
+
const nonce = randomBytes(32).toString('hex');
|
|
62
|
+
return { ok: true, nonce, userId: device.userId, deviceId };
|
|
63
|
+
}
|
|
64
|
+
async verifyChallenge(deviceId, nonce, signature, encryptionKey, headRegion) {
|
|
65
|
+
const logger = getLogger();
|
|
66
|
+
const device = this.storage.getDevice(deviceId);
|
|
67
|
+
if (!device || !device.publicKey) {
|
|
68
|
+
return { ok: false, code: 'device_not_found', message: 'Device not found' };
|
|
69
|
+
}
|
|
70
|
+
const publicKeyPem = importPublicKey(device.publicKey);
|
|
71
|
+
const valid = verifySignature(nonce, signature, publicKeyPem);
|
|
72
|
+
if (!valid) {
|
|
73
|
+
logger.warn('Challenge-response auth failed', { deviceId });
|
|
74
|
+
return { ok: false, code: 'invalid_signature', message: 'Invalid signature' };
|
|
75
|
+
}
|
|
76
|
+
// Update encryption key if provided
|
|
77
|
+
const updatedKey = encryptionKey ?? device.encryptionKey ?? undefined;
|
|
78
|
+
this.storage.upsertDevice(deviceId, device.userId, device.name, device.role, device.kind ?? undefined, device.publicKey ?? undefined, updatedKey);
|
|
79
|
+
const user = this.storage.getUser(device.userId);
|
|
80
|
+
if (!user) {
|
|
81
|
+
return { ok: false, code: 'user_not_found', message: 'User not found' };
|
|
82
|
+
}
|
|
83
|
+
// Region check
|
|
84
|
+
const regionCheck = this.checkRegion(user.userId, headRegion);
|
|
85
|
+
if (regionCheck)
|
|
86
|
+
return regionCheck;
|
|
87
|
+
return {
|
|
88
|
+
ok: true,
|
|
89
|
+
userId: user.userId,
|
|
90
|
+
deviceId,
|
|
91
|
+
authMethod: 'challenge',
|
|
92
|
+
user: {
|
|
93
|
+
id: user.userId,
|
|
94
|
+
login: user.username,
|
|
95
|
+
provider: user.provider,
|
|
96
|
+
email: user.email,
|
|
97
|
+
preferences: user.preferences,
|
|
98
|
+
region: user.region,
|
|
99
|
+
},
|
|
100
|
+
devices: this.getDeviceSummaries(user.userId),
|
|
101
|
+
pendingMessages: this.flushPending(deviceId),
|
|
102
|
+
githubClientId: this.getGitHubClientId(),
|
|
103
|
+
vapidPublicKey: this.getVapidPublicKey(),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
createPairingToken(userId) {
|
|
107
|
+
const token = `pt_${randomBytes(32).toString('hex')}`;
|
|
108
|
+
this.pairingTokens.set(token, {
|
|
109
|
+
userId,
|
|
110
|
+
expiresAt: Date.now() + this.pairingTtl * 1000,
|
|
111
|
+
});
|
|
112
|
+
return { token, expiresIn: this.pairingTtl };
|
|
113
|
+
}
|
|
114
|
+
async requestPairingToken(token, ip) {
|
|
115
|
+
// Try all providers
|
|
116
|
+
for (const provider of this.authProviders.values()) {
|
|
117
|
+
const result = await provider.authenticate({ token, ip });
|
|
118
|
+
if (result.ok) {
|
|
119
|
+
this.storage.upsertUser(result.user.id, result.user.login, result.user.provider, result.user.email);
|
|
120
|
+
const pairing = this.createPairingToken(result.user.id);
|
|
121
|
+
return { ok: true, userId: result.user.id, pairingToken: pairing.token, expiresIn: pairing.expiresIn };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return { ok: false, code: 'auth_rejected', message: 'No auth provider accepted the token' };
|
|
125
|
+
}
|
|
126
|
+
getAuthInfo() {
|
|
127
|
+
const methods = [];
|
|
128
|
+
if (this.authProviders.has('github')) {
|
|
129
|
+
methods.push('github_token');
|
|
130
|
+
const ghProvider = this.findGitHubProvider();
|
|
131
|
+
if (ghProvider?.oauthConfigured)
|
|
132
|
+
methods.push('github_oauth');
|
|
133
|
+
}
|
|
134
|
+
if (this.authProviders.has('apikey'))
|
|
135
|
+
methods.push('apikey');
|
|
136
|
+
if (this.authProviders.has('open'))
|
|
137
|
+
methods.push('open');
|
|
138
|
+
if (this.pairingEnabled)
|
|
139
|
+
methods.push('pairing');
|
|
140
|
+
methods.push('challenge');
|
|
141
|
+
return {
|
|
142
|
+
methods,
|
|
143
|
+
githubClientId: this.getGitHubClientId(),
|
|
144
|
+
vapidPublicKey: this.getVapidPublicKey(),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
async resolveLogin(auth, preferredRegion, clientIp) {
|
|
148
|
+
if (auth.method === 'pairing' || auth.method === 'challenge') {
|
|
149
|
+
return { ok: false, code: 'unsupported_auth_method', message: `${auth.method} cannot be used for login-first routing` };
|
|
150
|
+
}
|
|
151
|
+
const resolved = await this.resolveAuthUser(auth);
|
|
152
|
+
if (this.isAuthError(resolved))
|
|
153
|
+
return resolved;
|
|
154
|
+
const regions = this.getRegions();
|
|
155
|
+
const storedUser = this.storage.getUser(resolved.id);
|
|
156
|
+
const assignedRegion = storedUser?.region;
|
|
157
|
+
if (assignedRegion) {
|
|
158
|
+
return {
|
|
159
|
+
ok: true,
|
|
160
|
+
registered: true,
|
|
161
|
+
needsRegionSelection: false,
|
|
162
|
+
user: this.buildUserProfile(resolved, storedUser?.preferences, assignedRegion),
|
|
163
|
+
region: assignedRegion,
|
|
164
|
+
relayUrl: this.getRelayUrlForRegion(assignedRegion),
|
|
165
|
+
regions,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
// New user — auto-assign region from preferred, IP geo, or first available
|
|
169
|
+
let targetRegion = preferredRegion;
|
|
170
|
+
if (!targetRegion && clientIp) {
|
|
171
|
+
const geoRegion = await suggestRegionForIp(clientIp);
|
|
172
|
+
if (geoRegion && regions.some(r => r.code === geoRegion)) {
|
|
173
|
+
targetRegion = geoRegion;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (!targetRegion) {
|
|
177
|
+
targetRegion = this.region ?? regions[0]?.code;
|
|
178
|
+
}
|
|
179
|
+
if (targetRegion) {
|
|
180
|
+
const regionInfo = this.storage.getRegion(targetRegion);
|
|
181
|
+
if (regionInfo?.enabled) {
|
|
182
|
+
this.storage.upsertUser(resolved.id, resolved.login, resolved.provider, resolved.email, regionInfo.code);
|
|
183
|
+
this.storage.setUserRegion(resolved.id, regionInfo.code);
|
|
184
|
+
return {
|
|
185
|
+
ok: true,
|
|
186
|
+
registered: true,
|
|
187
|
+
needsRegionSelection: false,
|
|
188
|
+
user: this.buildUserProfile(resolved, storedUser?.preferences, regionInfo.code),
|
|
189
|
+
region: regionInfo.code,
|
|
190
|
+
relayUrl: regionInfo.relayUrl,
|
|
191
|
+
regions,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// Fallback: no regions configured — return without region assignment
|
|
196
|
+
this.storage.upsertUser(resolved.id, resolved.login, resolved.provider, resolved.email);
|
|
197
|
+
return {
|
|
198
|
+
ok: true,
|
|
199
|
+
registered: true,
|
|
200
|
+
needsRegionSelection: false,
|
|
201
|
+
user: this.buildUserProfile(resolved, storedUser?.preferences),
|
|
202
|
+
regions,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
getRegions() {
|
|
206
|
+
return this.storage.getRegions(true).map(region => ({
|
|
207
|
+
code: region.code,
|
|
208
|
+
relayUrl: region.relayUrl,
|
|
209
|
+
displayName: region.displayName,
|
|
210
|
+
}));
|
|
211
|
+
}
|
|
212
|
+
getRegionVersion() {
|
|
213
|
+
return this.storage.getRegionVersion();
|
|
214
|
+
}
|
|
215
|
+
completeEdgeJoin(token, region, relayUrl, displayName) {
|
|
216
|
+
const joinResult = this.storage.consumeEdgeJoinToken(token, region, relayUrl, displayName);
|
|
217
|
+
if (!joinResult.ok)
|
|
218
|
+
return joinResult;
|
|
219
|
+
this.storage.upsertRegion(joinResult.region, joinResult.relayUrl, joinResult.displayName, true);
|
|
220
|
+
const { serviceKey } = this.storage.issueRegionServiceKey(joinResult.region);
|
|
221
|
+
return {
|
|
222
|
+
ok: true,
|
|
223
|
+
region: joinResult.region,
|
|
224
|
+
relayUrl: joinResult.relayUrl,
|
|
225
|
+
displayName: joinResult.displayName,
|
|
226
|
+
serviceKey,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
validateServiceKey(serviceKey) {
|
|
230
|
+
const result = this.storage.validateServiceKey(serviceKey);
|
|
231
|
+
return result.valid ? { valid: true, region: result.region } : { valid: false };
|
|
232
|
+
}
|
|
233
|
+
/** Sweep expired pairing tokens. Called periodically by HeadServer. */
|
|
234
|
+
sweepPairingTokens() {
|
|
235
|
+
const now = Date.now();
|
|
236
|
+
for (const [token, data] of this.pairingTokens) {
|
|
237
|
+
if (now > data.expiresAt)
|
|
238
|
+
this.pairingTokens.delete(token);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
// ── Private helpers ───────────────────────────────────
|
|
242
|
+
handlePairingAuth(pairingToken, device, headRegion) {
|
|
243
|
+
const logger = getLogger();
|
|
244
|
+
if (!this.pairingEnabled) {
|
|
245
|
+
return { ok: false, code: 'pairing_disabled', message: 'Pairing is disabled.' };
|
|
246
|
+
}
|
|
247
|
+
const tokenData = this.pairingTokens.get(pairingToken);
|
|
248
|
+
if (!tokenData || tokenData.expiresAt < Date.now()) {
|
|
249
|
+
if (tokenData)
|
|
250
|
+
this.pairingTokens.delete(pairingToken);
|
|
251
|
+
logger.warn('Pairing auth failed: invalid or expired token');
|
|
252
|
+
return { ok: false, code: 'invalid_pairing_token', message: 'Invalid or expired pairing token' };
|
|
253
|
+
}
|
|
254
|
+
// Consume token (single-use)
|
|
255
|
+
this.pairingTokens.delete(pairingToken);
|
|
256
|
+
const user = this.storage.getUser(tokenData.userId);
|
|
257
|
+
if (!user) {
|
|
258
|
+
return { ok: false, code: 'user_not_found', message: 'User not found' };
|
|
259
|
+
}
|
|
260
|
+
const authUser = { id: user.userId, login: user.username, provider: user.provider, email: user.email };
|
|
261
|
+
return this.completeAuth(authUser, device, 'pairing', headRegion);
|
|
262
|
+
}
|
|
263
|
+
completeAuth(authUser, device, authMethod, headRegion) {
|
|
264
|
+
const logger = getLogger();
|
|
265
|
+
// Upsert user — assign region on first auth if not yet set
|
|
266
|
+
const existingUser = this.storage.getUser(authUser.id);
|
|
267
|
+
const userRegion = existingUser?.region ?? headRegion ?? this.region;
|
|
268
|
+
this.storage.upsertUser(authUser.id, authUser.login, authUser.provider, authUser.email, userRegion);
|
|
269
|
+
// If user already has a region and it doesn't match, set it now
|
|
270
|
+
if (userRegion && !existingUser?.region) {
|
|
271
|
+
this.storage.setUserRegion(authUser.id, userRegion);
|
|
272
|
+
}
|
|
273
|
+
// Region check
|
|
274
|
+
const regionCheck = this.checkRegion(authUser.id, headRegion);
|
|
275
|
+
if (regionCheck)
|
|
276
|
+
return regionCheck;
|
|
277
|
+
// Register device
|
|
278
|
+
const deviceId = device.deviceId ?? `dev_${uuid().slice(0, 12)}`;
|
|
279
|
+
try {
|
|
280
|
+
this.storage.upsertDevice(deviceId, authUser.id, device.name, device.role, device.kind, device.publicKey, device.encryptionKey);
|
|
281
|
+
}
|
|
282
|
+
catch (err) {
|
|
283
|
+
logger.warn('Device registration failed', { error: err.message });
|
|
284
|
+
return { ok: false, code: 'device_registration_failed', message: err.message };
|
|
285
|
+
}
|
|
286
|
+
const fullUser = this.storage.getUser(authUser.id);
|
|
287
|
+
return {
|
|
288
|
+
ok: true,
|
|
289
|
+
userId: authUser.id,
|
|
290
|
+
deviceId,
|
|
291
|
+
authMethod,
|
|
292
|
+
user: {
|
|
293
|
+
id: authUser.id,
|
|
294
|
+
login: authUser.login,
|
|
295
|
+
provider: authUser.provider,
|
|
296
|
+
email: authUser.email,
|
|
297
|
+
preferences: fullUser?.preferences,
|
|
298
|
+
region: fullUser?.region,
|
|
299
|
+
},
|
|
300
|
+
devices: this.getDeviceSummaries(authUser.id),
|
|
301
|
+
pendingMessages: this.flushPending(deviceId),
|
|
302
|
+
githubClientId: this.getGitHubClientId(),
|
|
303
|
+
vapidPublicKey: this.getVapidPublicKey(),
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
checkRegion(userId, headRegion) {
|
|
307
|
+
if (!this.region || !headRegion)
|
|
308
|
+
return null; // Region checks disabled
|
|
309
|
+
const user = this.storage.getUser(userId);
|
|
310
|
+
if (!user?.region)
|
|
311
|
+
return null; // User has no region yet
|
|
312
|
+
if (user.region === headRegion)
|
|
313
|
+
return null; // Correct region
|
|
314
|
+
const redirectUrl = this.getRelayUrlForRegion(user.region);
|
|
315
|
+
return {
|
|
316
|
+
ok: false,
|
|
317
|
+
code: 'wrong_region',
|
|
318
|
+
...(redirectUrl && { redirect: redirectUrl }),
|
|
319
|
+
message: redirectUrl
|
|
320
|
+
? `User is assigned to region '${user.region}', connect to ${redirectUrl}`
|
|
321
|
+
: `User is assigned to region '${user.region}'`,
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
async resolveAuthUser(auth) {
|
|
325
|
+
let provider;
|
|
326
|
+
let credentials = {};
|
|
327
|
+
switch (auth.method) {
|
|
328
|
+
case 'github_token':
|
|
329
|
+
provider = this.getProviderForMode('github');
|
|
330
|
+
credentials = { token: auth.token };
|
|
331
|
+
break;
|
|
332
|
+
case 'github_oauth':
|
|
333
|
+
provider = this.getProviderForMode('github');
|
|
334
|
+
credentials = { githubCode: auth.code };
|
|
335
|
+
break;
|
|
336
|
+
case 'apikey':
|
|
337
|
+
provider = this.getProviderForMode('apikey');
|
|
338
|
+
credentials = { token: auth.key };
|
|
339
|
+
break;
|
|
340
|
+
case 'open':
|
|
341
|
+
provider = this.getProviderForMode('open');
|
|
342
|
+
credentials = { token: auth.sharedKey };
|
|
343
|
+
break;
|
|
344
|
+
default:
|
|
345
|
+
return { ok: false, code: 'unknown_auth_method', message: `Unknown auth method: ${auth.method}` };
|
|
346
|
+
}
|
|
347
|
+
if (!provider) {
|
|
348
|
+
return { ok: false, code: 'auth_rejected', message: `Auth method ${auth.method} not configured` };
|
|
349
|
+
}
|
|
350
|
+
const result = await provider.authenticate(credentials);
|
|
351
|
+
if (!result.ok) {
|
|
352
|
+
return { ok: false, code: 'auth_rejected', message: result.message };
|
|
353
|
+
}
|
|
354
|
+
return result.user;
|
|
355
|
+
}
|
|
356
|
+
isAuthError(result) {
|
|
357
|
+
return 'ok' in result && result.ok === false;
|
|
358
|
+
}
|
|
359
|
+
buildUserProfile(authUser, preferences, region) {
|
|
360
|
+
return {
|
|
361
|
+
id: authUser.id,
|
|
362
|
+
login: authUser.login,
|
|
363
|
+
provider: authUser.provider,
|
|
364
|
+
email: authUser.email,
|
|
365
|
+
preferences,
|
|
366
|
+
region,
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
getRelayUrlForRegion(region) {
|
|
370
|
+
return this.storage.getRegion(region)?.relayUrl ?? this.regionUrls[region];
|
|
371
|
+
}
|
|
372
|
+
getProviderForMode(mode) {
|
|
373
|
+
return this.authProviders.get(mode);
|
|
374
|
+
}
|
|
375
|
+
findGitHubProvider() {
|
|
376
|
+
const provider = this.authProviders.get('github');
|
|
377
|
+
if (!provider)
|
|
378
|
+
return undefined;
|
|
379
|
+
if (provider instanceof GitHubAuthProvider)
|
|
380
|
+
return provider;
|
|
381
|
+
if ('inner' in provider) {
|
|
382
|
+
const inner = provider.inner;
|
|
383
|
+
if (inner instanceof GitHubAuthProvider)
|
|
384
|
+
return inner;
|
|
385
|
+
}
|
|
386
|
+
return undefined;
|
|
387
|
+
}
|
|
388
|
+
getGitHubClientId() {
|
|
389
|
+
return this.findGitHubProvider()?.oauthConfigured ? this.findGitHubProvider().getClientId() : undefined;
|
|
390
|
+
}
|
|
391
|
+
getVapidPublicKey() {
|
|
392
|
+
return this.pushManager?.getVapidPublicKey();
|
|
393
|
+
}
|
|
394
|
+
getDeviceSummaries(userId) {
|
|
395
|
+
const stored = this.storage.getDevicesByUser(userId);
|
|
396
|
+
return stored.map(d => ({
|
|
397
|
+
id: d.id,
|
|
398
|
+
name: d.name,
|
|
399
|
+
role: d.role,
|
|
400
|
+
kind: d.kind ?? undefined,
|
|
401
|
+
publicKey: d.publicKey ?? undefined,
|
|
402
|
+
encryptionKey: d.encryptionKey ?? undefined,
|
|
403
|
+
online: false, // HeadServer sets the correct online status
|
|
404
|
+
lastSeen: d.lastSeen,
|
|
405
|
+
createdAt: d.createdAt,
|
|
406
|
+
}));
|
|
407
|
+
}
|
|
408
|
+
flushPending(deviceId) {
|
|
409
|
+
const rows = this.storage.flushPending(deviceId);
|
|
410
|
+
const envelopes = [];
|
|
411
|
+
for (const raw of rows) {
|
|
412
|
+
try {
|
|
413
|
+
envelopes.push(JSON.parse(raw));
|
|
414
|
+
}
|
|
415
|
+
catch { /* skip malformed */ }
|
|
416
|
+
}
|
|
417
|
+
return envelopes;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
//# sourceMappingURL=local-auth-backend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-auth-backend.js","sourceRoot":"","sources":["../src/local-auth-backend.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Remote auth backend — delegates auth to a remote Account Service via REST.
|
|
3
|
+
* Used when head runs in connected mode (--account-url flag).
|
|
4
|
+
*/
|
|
5
|
+
import type { AuthMethod, DeviceInfo } from '@kraki/protocol';
|
|
6
|
+
import type { AuthBackend, AuthOutcome, ChallengeOutcome, AuthInfoConfig } from './auth-backend.js';
|
|
7
|
+
export interface RemoteAuthBackendOptions {
|
|
8
|
+
/** Account Service base URL (e.g., http://localhost:5000) */
|
|
9
|
+
accountUrl: string;
|
|
10
|
+
/** Service API key for authenticating with Account Service */
|
|
11
|
+
serviceKey: string;
|
|
12
|
+
/** Request timeout in ms. Default: 15000 */
|
|
13
|
+
timeout?: number;
|
|
14
|
+
}
|
|
15
|
+
export declare class RemoteAuthBackend implements AuthBackend {
|
|
16
|
+
private accountUrl;
|
|
17
|
+
private serviceKey;
|
|
18
|
+
private timeout;
|
|
19
|
+
private cachedConfig;
|
|
20
|
+
constructor(options: RemoteAuthBackendOptions);
|
|
21
|
+
authenticate(auth: AuthMethod, device: DeviceInfo, headRegion?: string): Promise<AuthOutcome>;
|
|
22
|
+
startChallenge(deviceId: string, encryptionKey?: string, headRegion?: string): Promise<ChallengeOutcome>;
|
|
23
|
+
verifyChallenge(deviceId: string, nonce: string, signature: string, encryptionKey?: string, headRegion?: string): Promise<AuthOutcome>;
|
|
24
|
+
createPairingToken(userId: string): {
|
|
25
|
+
token: string;
|
|
26
|
+
expiresIn: number;
|
|
27
|
+
};
|
|
28
|
+
/** Async version of createPairingToken for remote backend. */
|
|
29
|
+
createPairingTokenAsync(userId: string): Promise<{
|
|
30
|
+
token: string;
|
|
31
|
+
expiresIn: number;
|
|
32
|
+
}>;
|
|
33
|
+
requestPairingToken(token: string, ip?: string): Promise<{
|
|
34
|
+
ok: true;
|
|
35
|
+
userId: string;
|
|
36
|
+
pairingToken: string;
|
|
37
|
+
expiresIn: number;
|
|
38
|
+
} | {
|
|
39
|
+
ok: false;
|
|
40
|
+
code: string;
|
|
41
|
+
message: string;
|
|
42
|
+
}>;
|
|
43
|
+
getAuthInfo(): AuthInfoConfig;
|
|
44
|
+
/** Fetch config from Account Service. Call on startup and periodically. */
|
|
45
|
+
refreshConfig(): Promise<AuthInfoConfig>;
|
|
46
|
+
private post;
|
|
47
|
+
private get;
|
|
48
|
+
}
|