@acurast/cli
Version:
A cli to interact with the Acurast Cloud.
114 lines • 4.29 kB
JavaScript
import { LocalStorage } from './LocalStorage.js';
import { ACURAST_GLOBAL_BASE_PATH } from '../constants.js';
// Kept separate from `keys.json` (which the SDK KeyStore uses for ECDH keys).
const AUTH_FILE = 'auth.json';
const AUTH_KEY = 'auth';
// Logins older than this are treated as logged-out and require `acurast login`
// again. A remote login only authorises the browser wallet to be prompted, so a
// generous window is fine.
const SESSION_MAX_AGE_MS = 14 * 24 * 60 * 60 * 1000; // 14 days
// auth.json holds identity metadata — keep it readable only by the owner.
// The project store uses LocalStorage's default (cwd) base path.
const store = (scope) => scope === 'global'
? new LocalStorage(AUTH_FILE, 0o600, ACURAST_GLOBAL_BASE_PATH)
: new LocalStorage(AUTH_FILE, 0o600);
const isExpired = (record) => {
const at = Date.parse(record.loggedInAt);
if (Number.isNaN(at))
return false; // tolerate older records without a parseable date
return Date.now() - at > SESSION_MAX_AGE_MS;
};
/** The stored record as-is, without the expiry check. */
const parse = (scope) => {
const raw = store(scope).getItem(AUTH_KEY);
if (!raw)
return null;
try {
return JSON.parse(raw);
}
catch {
return null;
}
};
const read = (scope) => {
const record = parse(scope);
if (!record || isExpired(record))
return null;
return record;
};
export const getGlobalAuth = () => read('global');
export const getProjectAuth = () => read('project');
/**
* A stored login that exists but has aged out, if any (project pin first, to
* match `getActiveAuth`). Lets callers say "your session expired" instead of
* the misleading "ACURAST_MNEMONIC is not defined" they would otherwise hit
* once an expired session drops the signing mode back to `local`.
*/
export const getExpiredAuth = () => {
for (const scope of ['project', 'global']) {
const record = parse(scope);
if (record && isExpired(record))
return { scope, record };
}
return null;
};
/** The account that will actually be used: a project pin wins over the global login. */
export const getActiveAuth = () => getProjectAuth() ?? getGlobalAuth();
export const getLoggedInAddress = () => getActiveAuth()?.address;
export const isLoggedIn = () => getLoggedInAddress() !== undefined;
export const setAuth = (record, scope = 'global') => {
store(scope).setItem(AUTH_KEY, JSON.stringify(record));
};
export const clearAuth = (scope) => {
store(scope).removeItem(AUTH_KEY);
};
/** Update `lastUsedAt` on whichever scope provided the active account (best-effort). */
export const touchAuth = () => {
const now = new Date().toISOString();
const project = getProjectAuth();
if (project) {
setAuth({ ...project, lastUsedAt: now }, 'project');
return;
}
const global = getGlobalAuth();
if (global) {
setAuth({ ...global, lastUsedAt: now }, 'global');
}
};
/**
* Resolve the signing mode, highest priority first:
* 1. explicit `ACURAST_SIGNING_MODE=local|remote`;
* 2. a project pin (`./.acurast/auth.json`) → `remote`;
* 3. `ACURAST_MNEMONIC` present → `local`;
* 4. a global login (`~/.acurast/auth.json`) → `remote`;
* 5. otherwise `local`.
*
* An ambient global login never silently changes how an existing mnemonic
* project signs (step 3 beats step 4). A deliberate project pin does (step 2).
* Expired sessions count as logged-out (see `read`).
*/
export const getSigningMode = () => {
const explicit = process.env.ACURAST_SIGNING_MODE;
if (explicit === 'remote' || explicit === 'local') {
return explicit;
}
if (getProjectAuth())
return 'remote';
if (process.env.ACURAST_MNEMONIC)
return 'local';
if (getGlobalAuth())
return 'remote';
return 'local';
};
/** Where the account/key that will be used comes from — for `whoami` and deploy output. */
export const getAuthSource = () => {
if (getSigningMode() === 'remote') {
if (getProjectAuth())
return 'project';
if (getGlobalAuth())
return 'global';
return 'none';
}
return process.env.ACURAST_MNEMONIC ? 'mnemonic' : 'none';
};
//# sourceMappingURL=authStore.js.map