@appsemble/node-utils
Version:
NodeJS utilities used by Appsemble internally.
73 lines • 2.86 kB
JavaScript
import { AppsembleError, logger } from '@appsemble/node-utils';
import { select } from '@inquirer/prompts';
import axios from 'axios';
export const CREDENTIALS_ENV_VAR = 'APPSEMBLE_CLIENT_CREDENTIALS';
const authorizedRemotes = new Set();
export function getService(remote) {
return `appsemble://${new URL(remote).host}`;
}
export async function getKeytar() {
try {
const { default: keytar } = await import('keytar');
return keytar;
}
catch {
throw new AppsembleError('Couldn’t find module keytar. Either install libsecret and reinstall @appsemble/cli, or pass --client-credentials on the command line.');
}
}
async function getClientCredentials(remote, inputCredentials) {
if (inputCredentials) {
return inputCredentials;
}
const envCredentials = process.env[CREDENTIALS_ENV_VAR];
if (envCredentials) {
logger.info(`Detected client credentials from ${CREDENTIALS_ENV_VAR} environment variable`);
return envCredentials;
}
const { findCredentials } = await getKeytar();
const choices = await findCredentials(getService(remote));
if (choices.length === 0) {
throw new AppsembleError(`No client credentials found. Register them using:\n\nappsemble login --remote ${remote}`);
}
let choice;
if (choices.length === 1) {
[choice] = choices;
}
else {
choice = await select({
message: 'Select client id to use',
choices: choices.map((value) => ({ name: value.account, value })),
});
}
return `${choice.account}:${choice.password}`;
}
/**
* Login to the server using OAuth2 client credentials.
*
* @param remote Host to fetch token from.
* @param scope The OAuth2 scope to request. This may be space separated to request
* multiple scopes.
* @param inputCredentials Client credentials passed from the command line.
*/
export async function authenticate(remote, scope, inputCredentials) {
const credentials = await getClientCredentials(remote, inputCredentials);
if (authorizedRemotes.has(remote)) {
logger.verbose(`Already logged in to ${remote}`);
return;
}
logger.verbose(`Logging in to ${remote}`);
const { data } = await axios.post('/auth/oauth2/token', new URLSearchParams({ grant_type: 'client_credentials', scope }), {
headers: { authorization: `Basic ${Buffer.from(credentials).toString('base64')}` },
baseURL: remote,
});
authorizedRemotes.add(remote);
axios.interceptors.request.use((config) => {
if (config.baseURL === remote) {
config.headers.set('authorization', `Bearer ${data.access_token}`);
}
return config;
});
logger.info(`Logged in to ${remote} successfully`);
logger.verbose(`Login scope: ${scope}`);
}
//# sourceMappingURL=authentication.js.map