oidc-plus4u-vault
Version:
CLI tool for managing access codes for insomnia-plugin-oidc-plus4u.
172 lines (151 loc) • 5.97 kB
JavaScript
const TaskUtils = require("../misc/task-utils");
const HttpUtils = require("../misc/http-utils");
const OidcClient = require("../misc/oidc-client");
const AddTask = require("./add");
const SecureStoreCliCommon = require("../secure-store-cli-common");
const LineByLine = require('n-readlines');
const optionsDefinitions = [
{
name: "source",
alias: "s",
type: String,
description: "Source file for import."
},
{
name: "sourceType",
alias: "t",
type: String,
defaultValue: "vault",
description: "Type of source file - either 'vault' or 'txt' (from plus4u mall)."
},
{
name: "help",
alias: "h",
type: Boolean,
description: "Displays this usage guide."
},
{
name: "file",
alias: "f",
type: String,
description: "Path to vault file. This is useful if you want to manage project vault which other members of the team can import."
}
];
const help = [
{
header: "import command",
content: "Import user credentials from source file."
},
{
header: 'Synopsis',
content: [
'$ oidc-plus4u-vault import -s {underline source file}'
]
},
{
header: 'Options',
optionList: optionsDefinitions
}
];
class ImportTask {
constructor() {
this._taskUtils = new TaskUtils(optionsDefinitions, help);
}
async execute(cliArgs) {
let options = this._taskUtils.parseCliArguments(cliArgs);
this._taskUtils.testOption(options.source, "Source is mandatory option.");
if (options.sourceType === "vault") {
await this._importFromSecureStore(options);
} else if (options.sourceType === "txt") {
// enables load of multiple access codes stored in a text file in the copy-paste form returned in plus4u
await this._importFromPlus4uMallResponse(options);
} else {
throw new Error(`Unknown sourceType ${options.sourceType}.`);
}
}
async _importFromSecureStore(options) {
console.log(`Going to read source secure store ${options.source}`);
let sourceSecureStoreCliCommon = await this._loadVault(options.source);
let sourceSecureStore = await sourceSecureStoreCliCommon.readSecureStore();
console.log(`Going to import credentials to vault.`);
if (options.file) {
console.log(`Working with secure store on location ${options.file}`);
} else {
console.log(`Working with default secure store`);
}
let secureStoreCliCommon = await SecureStoreCliCommon.init(options.file);
let secureStoreCnt = await secureStoreCliCommon.readSecureStore();
console.info(`Importing ${Object.keys(sourceSecureStore).length} records...`);
secureStoreCnt = {...secureStoreCnt, ...sourceSecureStore};
await secureStoreCliCommon.writeSecureStore(secureStoreCnt);
console.info(`Import finished.`);
}
async _loadVault(uri) {
if (uri.toLowerCase().startsWith("http")) {
const defaultUser = await this._getLocalUser();
const token = await OidcClient.login(defaultUser.ac1, defaultUser.ac2, OidcClient.DEFAULT_OIDC_SERVER, uri);
console.info(`Downloading secure store from ${uri}.`);
const vaultBytes = await new HttpUtils(token).getResource(uri);
return SecureStoreCliCommon.loadFromBytes(vaultBytes);
} else {
return SecureStoreCliCommon.init(uri);
}
}
async _getLocalUser() {
console.info(`Loading default secure store to load credentials for HTTP call.`);
const defaultSecureStore = await SecureStoreCliCommon.init();
let users = await defaultSecureStore.readSecureStore();
const localUserKeys = ["you", "localUser"];
for(const userKey of localUserKeys) {
if (users.hasOwnProperty(userKey)) {
return users[userKey];
}
}
console.info(`Cannot find a local user with aliases (${localUserKeys}) in the default vault. Please provide credentials.`);
await new AddTask().execute(localUserKeys[0]);
users = await defaultSecureStore.readSecureStore();
return users[localUserKeys[0]];
}
async _importFromPlus4uMallResponse(options) {
let secureStoreCliCommon = await SecureStoreCliCommon.init(options.file);
let secureStoreCnt = await secureStoreCliCommon.readSecureStore();
const users = this._readUsersFromPlus4uMallResponse(options.source);
console.info(`Loaded ${Object.keys(users).length} users from the source file ${options.source}.`);
const oidcServer = options.oidcServer;
for (const userId in users) {
const user = users[userId];
if (await OidcClient.login(user.ac1, user.ac2, oidcServer)) {
user.oidcServer = oidcServer;
secureStoreCnt[userId] = user;
console.log(`Access code 1 and Access code 2 for user ${userId} has been successfully stored into secure store.`);
} else {
console.error(`Cannot login to oidc.plus4u.net with user ${userId}. Probably invalid combination of Access Code 1 and Access Code 2. Skipping this user...`);
}
}
secureStoreCliCommon.writeSecureStore(secureStoreCnt);
}
_readUsersFromPlus4uMallResponse(sourceFile) {
const users = {};
const lineReader = new LineByLine(sourceFile);
let lineBuf;
while (lineBuf = lineReader.next()) {
const line = lineBuf.toString();
if (!(line.length === 0 || !line.trim())) {
const parts = line.split(/[\t ]/g);
if (parts.length === 4) {
const user = parts[2];
const credentials = JSON.parse(parts[3]);
users[user] = {ac1: credentials.ac1, ac2: credentials.ac2};
} else if (parts.length === 3) {
const user = parts[1];
const credentials = JSON.parse(parts[2]);
users[user] = {ac1: credentials.ac1, ac2: credentials.ac2};
} else {
console.error(`Line cannot be parsed as it does not follow standard Expected 4 parts separated by tab or single space, but got ${parts.length}. Line: ${line}.`);
}
}
}
return users;
}
}
module.exports = ImportTask;