180 lines
5.0 KiB
JavaScript
180 lines
5.0 KiB
JavaScript
/**
|
|
* Copyright (c) HashiCorp, Inc.
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
*/
|
|
|
|
import ApplicationAdapter from '../application';
|
|
import { encodePath } from 'vault/utils/path-encoding-helpers';
|
|
import ControlGroupError from '../../lib/control-group-error';
|
|
import { inject as service } from '@ember/service';
|
|
|
|
function pickKeys(obj, picklist) {
|
|
const data = {};
|
|
Object.keys(obj).forEach((key) => {
|
|
if (picklist.indexOf(key) >= 0) {
|
|
data[key] = obj[key];
|
|
}
|
|
});
|
|
return data;
|
|
}
|
|
|
|
export default class KeymgmtKeyAdapter extends ApplicationAdapter {
|
|
@service store;
|
|
namespace = 'v1';
|
|
|
|
pathForType() {
|
|
// backend name prepended in buildURL method
|
|
return 'key';
|
|
}
|
|
|
|
buildURL(modelName, id, snapshot, requestType, query) {
|
|
let url = super.buildURL(...arguments);
|
|
if (snapshot) {
|
|
url = url.replace('key', `${snapshot.attr('backend')}/key`);
|
|
} else if (query) {
|
|
url = url.replace('key', `${query.backend}/key`);
|
|
}
|
|
return url;
|
|
}
|
|
|
|
url(backend, id, type) {
|
|
const url = `${this.buildURL()}/${backend}/key`;
|
|
if (id) {
|
|
if (type === 'ROTATE') {
|
|
return url + '/' + encodePath(id) + '/rotate';
|
|
} else if (type === 'PROVIDERS') {
|
|
return url + '/' + encodePath(id) + '/kms';
|
|
}
|
|
return url + '/' + encodePath(id);
|
|
}
|
|
return url;
|
|
}
|
|
|
|
_updateKey(backend, name, serialized) {
|
|
// Only these two attributes are allowed to be updated
|
|
const data = pickKeys(serialized, ['deletion_allowed', 'min_enabled_version']);
|
|
return this.ajax(this.url(backend, name), 'PUT', { data });
|
|
}
|
|
|
|
_createKey(backend, name, serialized) {
|
|
// Only type is allowed on create
|
|
const data = pickKeys(serialized, ['type']);
|
|
return this.ajax(this.url(backend, name), 'POST', { data });
|
|
}
|
|
|
|
async createRecord(store, type, snapshot) {
|
|
const data = store.serializerFor(type.modelName).serialize(snapshot);
|
|
const name = snapshot.attr('name');
|
|
const backend = snapshot.attr('backend');
|
|
// Keys must be created and then updated
|
|
await this._createKey(backend, name, data);
|
|
if (snapshot.attr('deletionAllowed')) {
|
|
try {
|
|
await this._updateKey(backend, name, data);
|
|
} catch {
|
|
throw new Error(`Key ${name} was created, but not all settings were saved`);
|
|
}
|
|
}
|
|
return {
|
|
data: {
|
|
...data,
|
|
id: name,
|
|
backend,
|
|
},
|
|
};
|
|
}
|
|
|
|
updateRecord(store, type, snapshot) {
|
|
const data = store.serializerFor(type.modelName).serialize(snapshot);
|
|
const name = snapshot.attr('name');
|
|
const backend = snapshot.attr('backend');
|
|
return this._updateKey(backend, name, data);
|
|
}
|
|
|
|
distribute(backend, kms, key, data) {
|
|
return this.ajax(`${this.buildURL()}/${backend}/kms/${encodePath(kms)}/key/${encodePath(key)}`, 'PUT', {
|
|
data: { ...data },
|
|
});
|
|
}
|
|
|
|
async getProvider(backend, name) {
|
|
try {
|
|
const resp = await this.ajax(this.url(backend, name, 'PROVIDERS'), 'GET', {
|
|
data: {
|
|
list: true,
|
|
},
|
|
});
|
|
return resp.data.keys ? resp.data.keys[0] : null;
|
|
} catch (e) {
|
|
if (e.httpStatus === 404) {
|
|
// No results, not distributed yet
|
|
return null;
|
|
} else if (e.httpStatus === 403) {
|
|
return { permissionsError: true };
|
|
}
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
getDistribution(backend, kms, key) {
|
|
const url = `${this.buildURL()}/${backend}/kms/${kms}/key/${key}`;
|
|
return this.ajax(url, 'GET')
|
|
.then((res) => {
|
|
return {
|
|
...res.data,
|
|
purposeArray: res.data.purpose.split(','),
|
|
};
|
|
})
|
|
.catch((e) => {
|
|
if (e instanceof ControlGroupError) {
|
|
throw e;
|
|
}
|
|
return null;
|
|
});
|
|
}
|
|
|
|
async queryRecord(store, type, query) {
|
|
const { id, backend, recordOnly = false } = query;
|
|
const keyData = await this.ajax(this.url(backend, id), 'GET');
|
|
keyData.data.id = id;
|
|
keyData.data.backend = backend;
|
|
let provider, distribution;
|
|
if (!recordOnly) {
|
|
provider = await this.getProvider(backend, id);
|
|
if (provider && !provider.permissionsError) {
|
|
distribution = await this.getDistribution(backend, provider, id);
|
|
}
|
|
}
|
|
return { ...keyData, provider, distribution };
|
|
}
|
|
|
|
async query(store, type, query) {
|
|
const { backend, provider } = query;
|
|
const providerAdapter = store.adapterFor('keymgmt/provider');
|
|
const url = provider ? providerAdapter.buildKeysURL(query) : this.url(backend);
|
|
|
|
return this.ajax(url, 'GET', {
|
|
data: {
|
|
list: true,
|
|
},
|
|
}).then((res) => {
|
|
res.backend = backend;
|
|
return res;
|
|
});
|
|
}
|
|
|
|
async rotateKey(backend, id) {
|
|
const keyModel = this.store.peekRecord('keymgmt/key', id);
|
|
const result = await this.ajax(this.url(backend, id, 'ROTATE'), 'PUT');
|
|
await keyModel.reload();
|
|
return result;
|
|
}
|
|
|
|
removeFromProvider(model) {
|
|
const url = `${this.buildURL()}/${model.backend}/kms/${model.provider}/key/${model.name}`;
|
|
return this.ajax(url, 'DELETE').then(() => {
|
|
model.provider = null;
|
|
});
|
|
}
|
|
}
|