@webiny/api-security-so-ddb
Version:
Security storage operations.
685 lines (683 loc) • 17.2 kB
JavaScript
;
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