@agoric/access-token
Advanced tools
Comparing version 0.4.22-dev-b8d6697.0 to 0.4.22-dev-b8d96c7.0
{ | ||
"name": "@agoric/access-token", | ||
"version": "0.4.22-dev-b8d6697.0+b8d6697", | ||
"version": "0.4.22-dev-b8d96c7.0+b8d96c7", | ||
"description": "Persistent credentials for Agoric users, backed by a simple JSON file", | ||
@@ -13,15 +13,19 @@ "type": "module", | ||
"test": "ava", | ||
"test:c8": "c8 $C8_OPTIONS ava --config=ava-nesm.config.js", | ||
"test:c8": "c8 --all $C8_OPTIONS ava", | ||
"test:xs": "exit 0", | ||
"lint": "run-s --continue-on-error lint:*", | ||
"lint-fix": "yarn lint:eslint --fix", | ||
"lint:eslint": "eslint ." | ||
"lint:eslint": "eslint .", | ||
"lint:types": "tsc" | ||
}, | ||
"dependencies": { | ||
"@agoric/assert": "0.6.1-dev-b8d6697.0+b8d6697", | ||
"n-readlines": "^1.0.0", | ||
"proper-lockfile": "^4.1.2", | ||
"tmp": "^0.2.1" | ||
}, | ||
"devDependencies": { | ||
"@types/n-readlines": "^1.0.3", | ||
"@types/proper-lockfile": "^4.1.2", | ||
"ava": "^5.3.0", | ||
"c8": "^7.13.0" | ||
"c8": "^10.1.2" | ||
}, | ||
@@ -33,7 +37,13 @@ "publishConfig": { | ||
"files": [ | ||
"test/**/test-*.js" | ||
"test/**/*.test.*" | ||
], | ||
"require": [ | ||
"@endo/init/debug.js" | ||
], | ||
"timeout": "2m" | ||
}, | ||
"gitHead": "b8d6697074b899630909440f0ea3caa519cdad44" | ||
"typeCoverage": { | ||
"atLeast": 83.97 | ||
}, | ||
"gitHead": "b8d96c7314cc9edd47b960876f23a88c18f70070" | ||
} |
@@ -9,2 +9,7 @@ import fs from 'fs'; | ||
// Adapted from https://stackoverflow.com/a/43866992/14073862 | ||
/** | ||
* @param {object} opts | ||
* @param {BufferEncoding} [opts.stringBase] | ||
* @param {number} [opts.byteLength] | ||
*/ | ||
export function generateAccessToken({ | ||
@@ -32,5 +37,9 @@ stringBase = 'base64url', | ||
* @param {string|number} port | ||
* @param {string} [sharedStateDir] | ||
* @returns {Promise<string>} | ||
*/ | ||
export async function getAccessToken(port) { | ||
export async function getAccessToken( | ||
port, | ||
sharedStateDir = path.join(os.homedir(), '.agoric'), | ||
) { | ||
if (typeof port === 'string') { | ||
@@ -44,14 +53,18 @@ const match = port.match(/^(.*:)?(\d+)$/); | ||
// Ensure we're protected with a unique accessToken for this basedir. | ||
const sharedStateDir = path.join(os.homedir(), '.agoric'); | ||
await fs.promises.mkdir(sharedStateDir, { mode: 0o700, recursive: true }); | ||
// Ensure an access token exists. | ||
const { storage, commit, close } = openJSONStore(sharedStateDir); | ||
const accessTokenKey = `accessToken/${port}`; | ||
if (!storage.has(accessTokenKey)) { | ||
storage.set(accessTokenKey, await generateAccessToken()); | ||
await commit(); | ||
const { storage, commit, close } = await openJSONStore(sharedStateDir); | ||
let accessToken; | ||
try { | ||
// Ensure an access token exists. | ||
const accessTokenKey = `accessToken/${port}`; | ||
if (!storage.has(accessTokenKey)) { | ||
storage.set(accessTokenKey, await generateAccessToken()); | ||
await commit(); | ||
} | ||
accessToken = storage.get(accessTokenKey); | ||
} finally { | ||
await close(); | ||
} | ||
const accessToken = storage.get(accessTokenKey); | ||
await close(); | ||
if (typeof accessToken !== 'string') { | ||
@@ -58,0 +71,0 @@ throw Error(`Could not find access token for ${port}`); |
@@ -5,2 +5,3 @@ // @ts-check | ||
import process from 'process'; | ||
import lockfile from 'proper-lockfile'; | ||
import Readlines from 'n-readlines'; | ||
@@ -15,2 +16,4 @@ | ||
const DEFAULT_LOCK_RETRIES = 10; | ||
/** | ||
@@ -161,12 +164,19 @@ * @typedef {ReturnType<typeof makeStorageInMemory>['storage']} JSONStore | ||
* @param {boolean} [forceReset] If true, initialize the database to an empty state | ||
* @param {null | import('proper-lockfile').LockOptions['retries']} [lockRetries] If null, do not lock the database. | ||
* | ||
* @returns {{ | ||
* @returns {Promise<{ | ||
* storage: JSONStore, // a storage API object to load and store data | ||
* commit: () => Promise<void>, // commit changes made since the last commit | ||
* close: () => Promise<void>, // shutdown the store, abandoning any uncommitted changes | ||
* }} | ||
* }>} | ||
*/ | ||
function makeJSONStore(dirPath, forceReset = false) { | ||
async function makeJSONStore( | ||
dirPath, | ||
forceReset = false, | ||
lockRetries = DEFAULT_LOCK_RETRIES, | ||
) { | ||
await null; | ||
const { storage, state } = makeStorageInMemory(); | ||
let releaseLock = async () => {}; | ||
let storeFile; | ||
@@ -176,2 +186,12 @@ if (dirPath) { | ||
storeFile = path.resolve(dirPath, DATA_FILE); | ||
if (lockRetries !== null) { | ||
// We need to lock the database to prevent multiple divergent instances. | ||
releaseLock = await lockfile.lock(dirPath, { | ||
// @ts-expect-error TS(2345) lockFilePath really does exist on LockOptions | ||
lockFilePath: `${storeFile}.lock`, | ||
retries: lockRetries, | ||
}); | ||
} | ||
if (forceReset) { | ||
@@ -193,4 +213,3 @@ safeUnlink(storeFile); | ||
while (line) { | ||
// @ts-expect-error JSON.parse can take a Buffer | ||
const [key, value] = JSON.parse(line); | ||
const [key, value] = JSON.parse(line.toString()); | ||
storage.set(key, value); | ||
@@ -203,2 +222,9 @@ line = lines.next(); | ||
const assertNotClosed = () => { | ||
if (!dirPath || storeFile) { | ||
return; | ||
} | ||
throw Error('JSON store is already closed'); | ||
}; | ||
/** | ||
@@ -208,2 +234,3 @@ * Commit unsaved changes. | ||
async function commit() { | ||
assertNotClosed(); | ||
if (dirPath) { | ||
@@ -215,4 +242,3 @@ const tempFile = `${storeFile}-${process.pid}.tmp`; | ||
const line = JSON.stringify([key, value]); | ||
fs.writeSync(fd, line); | ||
fs.writeSync(fd, '\n'); | ||
fs.writeSync(fd, `${line}\n`); | ||
} | ||
@@ -229,3 +255,5 @@ fs.closeSync(fd); | ||
async function close() { | ||
// Nothing to do here. | ||
assertNotClosed(); | ||
storeFile = undefined; | ||
await releaseLock(); | ||
} | ||
@@ -232,0 +260,0 @@ |
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
38608
10
497
4
+ Addedproper-lockfile@^4.1.2
+ Addedgraceful-fs@4.2.11(transitive)
+ Addedproper-lockfile@4.1.2(transitive)
+ Addedretry@0.12.0(transitive)
+ Addedsignal-exit@3.0.7(transitive)