| /** |
| * Copyright (c) HashiCorp, Inc. |
| * SPDX-License-Identifier: MPL-2.0 |
| */ |
| |
| /* eslint-disable */ |
| import AdapterError from '@ember-data/adapter/error'; |
| |
| import { isEmpty } from '@ember/utils'; |
| import { get } from '@ember/object'; |
| import ApplicationAdapter from './application'; |
| import { encodePath } from 'vault/utils/path-encoding-helpers'; |
| import { inject as service } from '@ember/service'; |
| |
| export default ApplicationAdapter.extend({ |
| store: service(), |
| namespace: 'v1', |
| |
| _url(backend, id, infix = 'data') { |
| let url = `${this.buildURL()}/${encodePath(backend)}/${infix}/`; |
| if (!isEmpty(id)) { |
| url = url + encodePath(id); |
| } |
| return url; |
| }, |
| |
| urlForFindRecord(id) { |
| let [backend, path, version] = JSON.parse(id); |
| let base = this._url(backend, path); |
| return version ? base + `?version=${version}` : base; |
| }, |
| |
| urlForQueryRecord(id) { |
| return this.urlForFindRecord(id); |
| }, |
| |
| findRecord() { |
| return this._super(...arguments).catch((errorOrModel) => { |
| // if the response is a real 404 or if the secret is gated by a control group this will be an error, |
| // otherwise the response will be the body of a deleted / destroyed version |
| if (errorOrModel instanceof AdapterError) { |
| throw errorOrModel; |
| } |
| return errorOrModel; |
| }); |
| }, |
| |
| async getSecretDataVersion(backend, id) { |
| // used in secret-edit route when you don't have current version and you need it for pulling the correct secret-v2-version record |
| let url = this._url(backend, id); |
| let response = await this.ajax(this._url(backend, id), 'GET'); |
| return response.data.metadata.version; |
| }, |
| |
| queryRecord(id, options) { |
| return this.ajax(this.urlForQueryRecord(id), 'GET', options).then((resp) => { |
| if (options.wrapTTL) { |
| return resp; |
| } |
| resp.id = id; |
| resp.backend = backend; |
| return resp; |
| }); |
| }, |
| |
| querySecretDataByVersion(id) { |
| return this.ajax(this.urlForQueryRecord(id), 'GET') |
| .then((resp) => { |
| return resp.data; |
| }) |
| .catch((error) => { |
| return error.data; |
| }); |
| }, |
| |
| urlForCreateRecord(modelName, snapshot) { |
| let backend = snapshot.belongsTo('secret').belongsTo('engine').id; |
| let path = snapshot.attr('path'); |
| return this._url(backend, path); |
| }, |
| |
| createRecord(store, modelName, snapshot) { |
| let backend = snapshot.belongsTo('secret').belongsTo('engine').id; |
| let path = snapshot.attr('path'); |
| return this._super(...arguments).then((resp) => { |
| resp.id = JSON.stringify([backend, path, resp.version]); |
| return resp; |
| }); |
| }, |
| |
| urlForUpdateRecord(id) { |
| let [backend, path] = JSON.parse(id); |
| return this._url(backend, path); |
| }, |
| |
| async deleteLatestVersion(backend, path) { |
| try { |
| await this.ajax(this._url(backend, path, 'data'), 'DELETE'); |
| let model = this.store.peekRecord('secret-v2-version', path); |
| await model.reload(); |
| return model && model.rollbackAttributes(); |
| } catch (e) { |
| return e; |
| } |
| }, |
| |
| async undeleteVersion(backend, path, currentVersionForNoReadMetadata) { |
| try { |
| await this.ajax(this._url(backend, path, 'undelete'), 'POST', { |
| data: { versions: [currentVersionForNoReadMetadata] }, |
| }); |
| let model = this.store.peekRecord('secret-v2-version', path); |
| await model.reload(); |
| return model && model.rollbackAttributes(); |
| } catch (e) { |
| return e; |
| } |
| }, |
| |
| async softDelete(backend, path, version) { |
| try { |
| await this.ajax(this._url(backend, path, 'delete'), 'POST', { |
| data: { versions: [version] }, |
| }); |
| let model = this.store.peekRecord('secret-v2-version', path); |
| await model.reload(); |
| return model && model.rollbackAttributes(); |
| } catch (e) { |
| return e; |
| } |
| }, |
| |
| async deleteByDeleteType(backend, path, deleteType, version) { |
| try { |
| await this.ajax(this._url(backend, path, deleteType), 'POST', { |
| data: { versions: [version] }, |
| }); |
| let model = this.store.peekRecord('secret-v2-version', path); |
| await model.reload(); |
| return model && model.rollbackAttributes(); |
| } catch (e) { |
| return e; |
| } |
| }, |
| |
| v2DeleteOperation(store, id, deleteType = 'delete', currentVersionForNoReadMetadata) { |
| let [backend, path, version] = JSON.parse(id); |
| // deleteType should be 'delete', 'destroy', 'undelete', 'delete-latest-version', 'destroy-version' |
| if ( |
| (currentVersionForNoReadMetadata && deleteType === 'delete') || |
| deleteType === 'delete-latest-version' |
| ) { |
| // moved to async to away model reload which is a promise |
| return this.deleteLatestVersion(backend, path); |
| } else if (deleteType === 'undelete' && !version) { |
| // happens when no read access to metadata |
| return this.undeleteVersion(backend, path, currentVersionForNoReadMetadata); |
| } else if (deleteType === 'soft-delete') { |
| return this.softDelete(backend, path, version); |
| } else { |
| version = version || currentVersionForNoReadMetadata; |
| return this.deleteByDeleteType(backend, path, deleteType, version); |
| } |
| }, |
| |
| handleResponse(status, headers, payload, requestData) { |
| // the body of the 404 will have some relevant information |
| if (status === 404 && get(payload, 'data.metadata')) { |
| return this._super(200, headers, payload, requestData); |
| } |
| return this._super(...arguments); |
| }, |
| }); |