UNPKG

@webiny/api-security-so-ddb

Version:
685 lines (683 loc) 17.2 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default; Object.defineProperty(exports, "__esModule", { value: true }); exports.createStorageOperations = void 0; var _types = require("./types"); var _error = _interopRequireDefault(require("@webiny/error")); var _table = require("./definitions/table"); var _entities = require("./definitions/entities"); var _dbDynamodb = require("@webiny/db-dynamodb"); const reservedFields = ["PK", "SK", "index", "data"]; const isReserved = name => { if (reservedFields.includes(name) === false) { return; } throw new _error.default(`Attribute name "${name}" is not allowed.`, "ATTRIBUTE_NOT_ALLOWED", { name }); }; const createStorageOperations = params => { const { table: tableName, documentClient, attributes } = params; if (attributes) { Object.values(attributes).forEach(attrs => { Object.keys(attrs).forEach(isReserved); }); } const table = (0, _table.createTable)({ table: tableName, documentClient }); const entities = { apiKeys: (0, _entities.createApiKeyEntity)(table, attributes ? attributes[_types.ENTITIES.API_KEY] : {}), system: (0, _entities.createSystemEntity)(table, attributes ? attributes[_types.ENTITIES.SYSTEM] : {}), groups: (0, _entities.createGroupEntity)(table, attributes ? attributes[_types.ENTITIES.GROUP] : {}), teams: (0, _entities.createTeamEntity)(table, attributes ? attributes[_types.ENTITIES.TEAM] : {}), tenantLinks: (0, _entities.createTenantLinkEntity)(table, attributes ? attributes[_types.ENTITIES.TENANT_LINK] : {}) }; const createApiKeyKeys = ({ id, tenant }) => ({ PK: `T#${tenant}#API_KEY#${id}`, SK: `A` }); const createGroupKeys = group => ({ PK: `T#${group.tenant}#GROUP#${group.id}`, SK: `A` }); const createGroupGsiKeys = group => ({ GSI1_PK: `T#${group.tenant}#GROUPS`, GSI1_SK: group.slug }); const createTeamKeys = team => ({ PK: `T#${team.tenant}#TEAM#${team.id}`, SK: `A` }); const createTeamGsiKeys = team => ({ GSI1_PK: `T#${team.tenant}#TEAMS`, GSI1_SK: team.slug }); const createSystemKeys = tenant => ({ PK: `T#${tenant}#SYSTEM`, SK: "SECURITY" }); return { async createApiKey({ apiKey }) { const keys = { ...createApiKeyKeys(apiKey), GSI1_PK: `T#${apiKey.tenant}#API_KEYS`, GSI1_SK: apiKey.token }; try { await (0, _dbDynamodb.put)({ entity: entities.apiKeys, item: { ...(0, _dbDynamodb.cleanupItem)(entities.apiKeys, apiKey), TYPE: "security.apiKey", ...keys } }); return apiKey; } catch (err) { throw _error.default.from(err, { message: "Could not create api key.", code: "CREATE_API_KEY_ERROR", data: { keys } }); } }, async createGroup({ group }) { const keys = { ...createGroupKeys(group), ...createGroupGsiKeys(group) }; try { await (0, _dbDynamodb.put)({ entity: entities.groups, item: { ...(0, _dbDynamodb.cleanupItem)(entities.groups, group), TYPE: "security.group", ...keys } }); return group; } catch (err) { throw _error.default.from(err, { message: "Could not create group.", code: "CREATE_GROUP_ERROR", data: { keys } }); } }, async createTeam({ team }) { const keys = { ...createTeamKeys(team), ...createTeamGsiKeys(team) }; try { await (0, _dbDynamodb.put)({ entity: entities.teams, item: { ...(0, _dbDynamodb.cleanupItem)(entities.teams, team), TYPE: "security.team", ...keys } }); return team; } catch (err) { throw _error.default.from(err, { message: "Could not create team.", code: "CREATE_TEAM_ERROR", data: { keys } }); } }, async createSystemData({ system }) { const keys = createSystemKeys(system.tenant); try { await (0, _dbDynamodb.put)({ entity: entities.system, item: { ...keys, ...(0, _dbDynamodb.cleanupItem)(entities.system, system) } }); return system; } catch (err) { throw _error.default.from(err, { message: "Could not create system.", code: "CREATE_SYSTEM_ERROR", data: { keys, system } }); } }, async createTenantLinks(links) { const batchWrite = (0, _dbDynamodb.createEntityWriteBatch)({ entity: entities.tenantLinks, put: links.map(link => { return { PK: `IDENTITY#${link.identity}`, SK: `LINK#T#${link.tenant}`, GSI1_PK: `T#${link.tenant}`, GSI1_SK: `TYPE#${link.type}#IDENTITY#${link.identity}`, ...(0, _dbDynamodb.cleanupItem)(entities.tenantLinks, link) }; }) }); await batchWrite.execute(); }, async deleteApiKey({ apiKey }) { const keys = createApiKeyKeys(apiKey); try { await (0, _dbDynamodb.deleteItem)({ entity: entities.apiKeys, keys }); } catch (err) { throw _error.default.from(err, { message: "Could not update api key.", code: "UPDATE_API_KEY_ERROR", data: { keys } }); } }, async deleteGroup({ group }) { const keys = createGroupKeys(group); try { await (0, _dbDynamodb.deleteItem)({ entity: entities.groups, keys }); } catch (err) { throw _error.default.from(err, { message: "Could not delete group.", code: "CREATE_DELETE_ERROR", data: { keys, group } }); } }, async deleteTeam({ team }) { const keys = createTeamKeys(team); try { await (0, _dbDynamodb.deleteItem)({ entity: entities.teams, keys }); } catch (err) { throw _error.default.from(err, { message: "Could not delete team.", code: "CREATE_DELETE_ERROR", data: { keys, team } }); } }, async deleteTenantLinks(links) { const batchWrite = (0, _dbDynamodb.createEntityWriteBatch)({ entity: entities.tenantLinks, delete: links.map(link => { return { PK: `IDENTITY#${link.identity}`, SK: `LINK#T#${link.tenant}` }; }) }); await batchWrite.execute(); }, async getApiKey({ id, tenant }) { const keys = createApiKeyKeys({ id, tenant }); try { return await (0, _dbDynamodb.getClean)({ entity: entities.apiKeys, keys }); } catch (err) { throw _error.default.from(err, { message: "Could not load api key.", code: "GET_API_KEY_ERROR", data: { id, keys } }); } }, async getApiKeyByToken({ tenant, token }) { const queryParams = { entity: entities.apiKeys, partitionKey: `T#${tenant}#API_KEYS`, options: { eq: token, index: "GSI1" } }; try { return await (0, _dbDynamodb.queryOneClean)(queryParams); } catch (err) { throw _error.default.from(err, { message: "Could not load api key by token.", code: "GET_BY_TOKEN_API_KEY_ERROR", data: { partitionKey: queryParams.partitionKey, options: queryParams.options } }); } }, async getGroup({ where: { tenant, id, slug } }) { try { if (id) { return await (0, _dbDynamodb.getClean)({ entity: entities.groups, keys: createGroupKeys({ tenant, id }) }); } return await (0, _dbDynamodb.queryOneClean)({ entity: entities.groups, partitionKey: `T#${tenant}#GROUPS`, options: { index: "GSI1", eq: slug } }); } catch (err) { throw _error.default.from(err, { message: "Could not load group.", code: "GET_GROUP_ERROR", data: { id, slug } }); } }, async getTeam({ where: { tenant, id, slug } }) { try { if (id) { return await (0, _dbDynamodb.getClean)({ entity: entities.teams, keys: createTeamKeys({ tenant, id }) }); } return await (0, _dbDynamodb.queryOneClean)({ entity: entities.teams, partitionKey: `T#${tenant}#TEAMS`, options: { index: "GSI1", eq: slug } }); } catch (err) { throw _error.default.from(err, { message: "Could not load team.", code: "GET_TEAM_ERROR", data: { id, slug } }); } }, async getSystemData({ tenant }) { const keys = createSystemKeys(tenant); try { return await (0, _dbDynamodb.getClean)({ entity: entities.system, keys }); } catch (err) { throw _error.default.from(err, { message: "Could not load system.", code: "GET_SYSTEM_ERROR", data: { keys } }); } }, async getTenantLinkByIdentity({ tenant, identity }) { try { return await (0, _dbDynamodb.queryOneClean)({ entity: entities.tenantLinks, partitionKey: `IDENTITY#${identity}`, options: { eq: `LINK#T#${tenant}` } }); } catch (err) { throw _error.default.from(err, { message: "Could not get tenant link for identity.", code: "GET_TENANT_LINK_BY_IDENTITY", data: { tenant, identity } }); } }, async listApiKeys({ where: { tenant }, sort }) { let items = []; try { items = await (0, _dbDynamodb.queryAll)({ entity: entities.apiKeys, partitionKey: `T#${tenant}#API_KEYS`, options: { index: "GSI1" } }); } catch (err) { throw _error.default.from(err, { message: "Could not list api keys.", code: "LIST_API_KEY_ERROR" }); } const sortedItems = (0, _dbDynamodb.sortItems)({ items, sort, fields: [] }); return sortedItems.map(item => (0, _dbDynamodb.cleanupItem)(entities.apiKeys, item)).filter(Boolean); }, async listGroups({ where: { tenant, id_in, slug_in }, sort }) { let items; try { items = await (0, _dbDynamodb.queryAll)({ entity: entities.groups, partitionKey: `T#${tenant}#GROUPS`, options: { index: "GSI1" } }); } catch (err) { throw _error.default.from(err, { message: "Could not list groups.", code: "LIST_GROUP_ERROR" }); } items = (0, _dbDynamodb.cleanupItems)(entities.groups, (0, _dbDynamodb.sortItems)({ items, sort, fields: [] })); if (Array.isArray(id_in)) { return items.filter(item => id_in.includes(item.id)); } if (Array.isArray(slug_in)) { return items.filter(item => slug_in.includes(item.slug)); } return items; }, async listTeams({ where: { tenant, id_in, slug_in }, sort }) { let items; try { items = await (0, _dbDynamodb.queryAll)({ entity: entities.teams, partitionKey: `T#${tenant}#TEAMS`, options: { index: "GSI1" } }); } catch (err) { throw _error.default.from(err, { message: "Could not list teams.", code: "LIST_TEAM_ERROR" }); } items = (0, _dbDynamodb.cleanupItems)(entities.teams, (0, _dbDynamodb.sortItems)({ items, sort, fields: [] })); if (Array.isArray(id_in)) { return items.filter(item => id_in.includes(item.id)); } if (Array.isArray(slug_in)) { return items.filter(item => slug_in.includes(item.slug)); } return items; }, async listTenantLinksByIdentity({ identity }) { return await (0, _dbDynamodb.queryAllClean)({ entity: entities.tenantLinks, partitionKey: `IDENTITY#${identity}`, options: { beginsWith: "LINK#" } }); }, async listTenantLinksByTenant({ tenant }) { return await (0, _dbDynamodb.queryAllClean)({ entity: entities.tenantLinks, partitionKey: `T#${tenant}`, options: { index: "GSI1" } }); }, async listTenantLinksByType({ type, tenant }) { return await (0, _dbDynamodb.queryAllClean)({ entity: entities.tenantLinks, partitionKey: `T#${tenant}`, options: { index: "GSI1", beginsWith: `TYPE#${type}#` } }); }, async updateApiKey({ apiKey }) { const keys = { ...createApiKeyKeys(apiKey), GSI1_PK: `T#${apiKey.tenant}#API_KEYS`, GSI1_SK: apiKey.token }; try { await (0, _dbDynamodb.put)({ entity: entities.apiKeys, item: { ...apiKey, TYPE: "security.apiKey", ...keys } }); return apiKey; } catch (err) { throw _error.default.from(err, { message: "Could not update api key.", code: "UPDATE_API_KEY_ERROR", data: { keys } }); } }, async updateGroup({ group }) { const keys = createGroupKeys(group); try { await (0, _dbDynamodb.put)({ entity: entities.groups, item: { ...(0, _dbDynamodb.cleanupItem)(entities.groups, group), ...keys, ...createGroupGsiKeys(group) } }); return group; } catch (err) { throw _error.default.from(err, { message: "Could not update group.", code: "UPDATE_GROUP_ERROR", data: { keys, group } }); } }, async updateTeam({ team }) { const keys = createTeamKeys(team); try { await (0, _dbDynamodb.put)({ entity: entities.teams, item: { ...(0, _dbDynamodb.cleanupItem)(entities.teams, team), ...keys, ...createTeamGsiKeys(team) } }); return team; } catch (err) { throw _error.default.from(err, { message: "Could not update team.", code: "UPDATE_TEAM_ERROR", data: { keys, team } }); } }, async updateSystemData({ system, original }) { const keys = createSystemKeys(system.tenant); try { await (0, _dbDynamodb.put)({ entity: entities.system, item: { ...keys, ...(0, _dbDynamodb.cleanupItem)(entities.system, system) } }); return system; } catch (err) { throw _error.default.from(err, { message: "Could not update system.", code: "UPDATE_SYSTEM_ERROR", data: { keys, system, original } }); } }, async updateTenantLinks(links) { const batchWrite = (0, _dbDynamodb.createEntityWriteBatch)({ entity: entities.tenantLinks, put: links.map(link => { return { PK: `IDENTITY#${link.identity}`, SK: `LINK#T#${link.tenant}`, GSI1_PK: `T#${link.tenant}`, GSI1_SK: `TYPE#${link.type}#IDENTITY#${link.identity}`, ...(0, _dbDynamodb.cleanupItem)(entities.tenantLinks, link) }; }) }); await batchWrite.execute(); } }; }; exports.createStorageOperations = createStorageOperations; //# sourceMappingURL=index.js.map