@sap/cli-core
Version:
Command-Line Interface (CLI) Core Module
150 lines (149 loc) • 5.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SecretsStorageImpl = void 0;
const constants_1 = require("../../constants");
const logger_1 = require("../../logger");
const utils_1 = require("../../logger/utils");
const types_1 = require("../../types");
const cache_1 = require("../cache");
const utils_2 = require("./utils");
class SecretsStorageImpl {
secrets = [];
logger;
constructor() {
this.logger = (0, logger_1.get)("SecretsStorageImpl");
}
async deleteAllSecrets() {
await (0, cache_1.deleteFile)(constants_1.CACHE_SECRETS_FILE);
this.secrets = [];
}
async recreateCalculatedValues() {
for (let i = 0; i < this.secrets.length; i++) {
this.secrets[i].id = i;
if (this.secrets[i].client_id) {
this.secrets[i].customClient = (0, utils_2.isCustomClient)(this.secrets[i].client_id);
// eslint-disable-next-line no-await-in-loop
await this.updateUrls(i);
}
else {
this.logger.warn(`client id is not set for secret with ID ${i}, skipping update of secret information`);
}
}
}
async initializeStorage() {
try {
this.secrets = JSON.parse(await (0, cache_1.readFile)(constants_1.CACHE_SECRETS_FILE));
if (!Array.isArray(this.secrets)) {
this.logger.warn("secrets data is no array, initializing secrets to empty array");
this.secrets = [];
}
this.removeInconsistentSecrets();
await this.recreateCalculatedValues();
}
catch (err) {
(0, utils_1.logVerbose)(this.logger, "The secrets file could not be read.");
this.logger.warn("failed to read or parse secrets file", err);
}
}
async getDefaultSecret() {
return this.getSecretById(await this.getDefaultSecretId());
}
async getDefaultSecretId() {
const tenantUrl = (0, utils_2.getTenantUrl)();
const { host } = new URL(tenantUrl);
const secret = this.secrets.find((s) => new URL(s.tenantUrl).host === host);
if (!secret) {
throw new Error(`No secret found for host ${host}`);
}
return secret.id;
}
ensureSecretsExist(id) {
return !!this.secrets.at(id);
}
throwIfSecretsDoesntExist(id) {
if (!this.ensureSecretsExist(id)) {
throw new Error(`no secrets exist for id ${id}`);
}
}
async getSecretById(id) {
this.throwIfSecretsDoesntExist(id);
return this.secrets.at(id);
}
removeSecretsFromArray(id) {
this.secrets.splice(id, 1);
}
updateSecret(secret) {
const tenantUrl = (0, utils_2.getTenantUrl)();
let prevSecretIx = this.secrets.findIndex((s) => s.tenantUrl === tenantUrl);
let newSecret;
if (prevSecretIx > -1) {
// Overwrite the old secret completely except for id and tenantUrl
newSecret = {
...secret,
id: this.secrets[prevSecretIx].id,
tenantUrl,
customClient: false,
};
this.secrets[prevSecretIx] = newSecret;
}
else {
newSecret = {
...secret,
id: this.secrets.length,
tenantUrl,
customClient: false,
};
this.secrets.push(newSecret);
prevSecretIx = this.secrets.length - 1;
}
return prevSecretIx;
}
async updateUrls(secretIndex) {
this.secrets[secretIndex] = await (0, utils_2.updateUrls)(this.secrets[secretIndex]);
}
async storeSecret(secret) {
this.updateSecret(secret);
await this.recreateCalculatedValues();
}
deleteSecretById(id) {
this.throwIfSecretsDoesntExist(id);
this.removeSecretsFromArray(id);
}
removeInconsistentSecrets() {
this.secrets = this.secrets.filter((secret) => {
const consistent = (0, utils_2.isSecretConsistent)(secret);
if (!consistent.consistent) {
this.logger.warn(`secret ${JSON.stringify(secret)} is not consistent and removed from cache. ${consistent.errors.join(". ")}`);
return false;
}
return true;
});
}
removeUnknownPropertiesFromSecrets() {
this.secrets.forEach((secret) => {
Object.keys(secret).forEach((key) => {
if (!types_1.ALLOWED_SECRET_TYPES.includes(key)) {
// eslint-disable-next-line no-param-reassign
delete secret[key];
}
});
});
}
async synchronizeSecretsToStorage() {
try {
this.removeInconsistentSecrets();
this.removeUnknownPropertiesFromSecrets();
await (0, cache_1.writeFile)(constants_1.CACHE_SECRETS_FILE, JSON.stringify(this.secrets));
}
catch (err) {
this.logger.error("failed to synchronize secrets to storage", err);
}
}
getAllSecrets() {
return this.secrets;
}
hasSecretForTenant(tenantUrl) {
return this.secrets.some((secret) => secret.tenantUrl === tenantUrl);
}
}
exports.SecretsStorageImpl = SecretsStorageImpl;