@tomato414941/foundation 0.27.0 → 0.28.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/package.json +1 -1
- package/runtime.mjs +8 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tomato414941/foundation",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.0",
|
|
4
4
|
"description": "Foundation CLI: give this machine a WebAuthn credential, and hand what is kept to a command without it passing through the agent.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
package/runtime.mjs
CHANGED
|
@@ -251,9 +251,9 @@ async function main() {
|
|
|
251
251
|
let key = publicSpec ? null : await readKey(keyPath, { missingOk: action === 'init' }), token = key?.token ?? null;
|
|
252
252
|
// The credential proves this machine for an hour at a time: the challenge is answered for the server actually reached.
|
|
253
253
|
async function prove() {
|
|
254
|
-
const begin = await fetch(url.origin + '/v1/session', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ kind: 'webauthn' }), redirect: 'error', signal: AbortSignal.timeout(30_000) });
|
|
254
|
+
const begin = await fetch(url.origin + '/v1/session/challenges', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ kind: 'webauthn' }), redirect: 'error', signal: AbortSignal.timeout(30_000) });
|
|
255
255
|
const { options } = await begin.json();
|
|
256
|
-
const response = await fetch(url.origin + '/v1/session', { method: '
|
|
256
|
+
const response = await fetch(url.origin + '/v1/session', { method: 'POST', headers: { 'content-type': 'application/json' },
|
|
257
257
|
body: JSON.stringify({ kind: 'webauthn', credential: answer(options, key.credential, url.origin), session: 'token' }), redirect: 'error', signal: AbortSignal.timeout(30_000) });
|
|
258
258
|
const proven = await response.json();
|
|
259
259
|
if (!response.ok || typeof proven.token !== 'string') throw new Error('Foundation did not accept this machine\'s credential (' + response.status + ', ' + (proven.error?.code || 'unknown') + ').');
|
|
@@ -271,9 +271,9 @@ async function main() {
|
|
|
271
271
|
async function upgrade(label) {
|
|
272
272
|
const me = await send('/v1/principals/me', undefined, { method: 'GET' });
|
|
273
273
|
if ((await send('/v1/session', undefined, { method: 'GET' })).current?.via.environment) return;
|
|
274
|
-
const { options } = await send('/v1/principals/' + encodeURIComponent(me.principal.id) + '/credentials', { kind: 'webauthn' });
|
|
274
|
+
const { options } = await send('/v1/principals/' + encodeURIComponent(me.principal.id) + '/credentials/challenges', { kind: 'webauthn' });
|
|
275
275
|
const made = createCredential(options, url.origin);
|
|
276
|
-
await send('/v1/principals/' + encodeURIComponent(me.principal.id) + '/credentials', { kind: 'webauthn', name: label, credential: made.response }
|
|
276
|
+
await send('/v1/principals/' + encodeURIComponent(me.principal.id) + '/credentials', { kind: 'webauthn', name: label, credential: made.response });
|
|
277
277
|
await writeKey(keyPath, JSON.stringify({ webauthn_credential: made.credential }), !process.env.FOUNDATION_RUNTIME_KEY_FILE);
|
|
278
278
|
key = { credential: made.credential };
|
|
279
279
|
}
|
|
@@ -282,7 +282,7 @@ async function main() {
|
|
|
282
282
|
async function publishKey() {
|
|
283
283
|
if (key.own) return;
|
|
284
284
|
const made = generateKey();
|
|
285
|
-
const published = await send('/v1/principals/me/key', { public_key: made.publicKey.toString('base64url') }, { method: 'PUT', accept: data => data.error?.code === 'key_exists' });
|
|
285
|
+
const published = await send('/v1/principals/me/encryption-key', { public_key: made.publicKey.toString('base64url') }, { method: 'PUT', accept: data => data.error?.code === 'key_exists' });
|
|
286
286
|
if (published.error) return;
|
|
287
287
|
key.own = { private_key: made.privateKey.toString('base64url') };
|
|
288
288
|
await writeKey(keyPath, JSON.stringify({ webauthn_credential: key.credential, key: key.own }), !process.env.FOUNDATION_RUNTIME_KEY_FILE);
|
|
@@ -315,12 +315,12 @@ async function main() {
|
|
|
315
315
|
// No key, or one this server does not know: a WebAuthn credential made here, proven by nobody, makes this machine a
|
|
316
316
|
// principal there, of nobody's - the same call a browser's passkey makes.
|
|
317
317
|
key = null; me = null;
|
|
318
|
-
const post = (
|
|
319
|
-
const begun = await post('
|
|
318
|
+
const post = (path, payload) => fetch(url.origin + path, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(payload), redirect: 'error', signal: AbortSignal.timeout(30_000) });
|
|
319
|
+
const begun = await post('/v1/principals/challenges', { kind: 'webauthn', name: wanted });
|
|
320
320
|
const { options, error } = await begun.json();
|
|
321
321
|
if (!begun.ok) throw new Error('Foundation did not begin a credential (' + begun.status + ', ' + (error?.code || 'unknown') + ').');
|
|
322
322
|
const made = createCredential(options, url.origin);
|
|
323
|
-
const done = await post('
|
|
323
|
+
const done = await post('/v1/principals', { kind: 'webauthn', name: wanted, principal_name: wanted, credential: made.response, session: 'token' });
|
|
324
324
|
const became = await done.json();
|
|
325
325
|
if (!done.ok || typeof became.token !== 'string') throw new Error('Foundation did not accept this machine\'s credential (' + done.status + ', ' + (became.error?.code || 'unknown') + ').');
|
|
326
326
|
key = { credential: made.credential }; token = became.token;
|