unleash-server
Version:
Unleash is an enterprise ready feature toggles service. It provides different strategies for handling feature toggles.
333 lines • 11.9 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AccessStore = void 0;
const metrics_helper_1 = __importDefault(require("../util/metrics-helper"));
const metric_events_1 = require("../metric-events");
const notfound_error_1 = __importDefault(require("../error/notfound-error"));
const constants_1 = require("../util/constants");
const T = {
ROLE_USER: 'role_user',
ROLES: 'roles',
GROUPS: 'groups',
GROUP_ROLE: 'group_role',
GROUP_USER: 'group_user',
ROLE_PERMISSION: 'role_permission',
PERMISSIONS: 'permissions',
PERMISSION_TYPES: 'permission_types',
CHANGE_REQUEST_SETTINGS: 'change_request_settings',
PERSONAL_ACCESS_TOKENS: 'personal_access_tokens',
PUBLIC_SIGNUP_TOKENS_USER: 'public_signup_tokens_user',
};
class AccessStore {
constructor(db, eventBus, getLogger) {
this.db = db;
this.logger = getLogger('access-store.ts');
this.timer = (action) => metrics_helper_1.default.wrapTimer(eventBus, metric_events_1.DB_TIME, {
store: 'access-store',
action,
});
}
async delete(key) {
await this.db(T.ROLES).where({ id: key }).del();
}
async deleteAll() {
await this.db(T.ROLES).del();
}
destroy() { }
async exists(key) {
const result = await this.db.raw(`SELECT EXISTS(SELECT 1 FROM ${T.ROLES} WHERE id = ?) AS present`, [key]);
const { present } = result.rows[0];
return present;
}
async get(key) {
const role = await this.db
.select(['id', 'name', 'type', 'description'])
.where('id', key)
.first()
.from(T.ROLES);
if (!role) {
throw new notfound_error_1.default(`Could not find role with id: ${key}`);
}
return role;
}
async getAll() {
return Promise.resolve([]);
}
async getAvailablePermissions() {
const rows = await this.db
.select(['id', 'permission', 'type', 'display_name'])
.where('type', 'project')
.orWhere('type', 'environment')
.from(`${T.PERMISSIONS} as p`);
return rows.map(this.mapPermission);
}
mapPermission(permission) {
return {
id: permission.id,
name: permission.permission,
displayName: permission.display_name,
type: permission.type,
};
}
async getPermissionsForUser(userId) {
const stopTimer = this.timer('getPermissionsForUser');
let userPermissionQuery = this.db
.select('project', 'permission', 'environment', 'type', 'ur.role_id')
.from(`${T.ROLE_PERMISSION} AS rp`)
.join(`${T.ROLE_USER} AS ur`, 'ur.role_id', 'rp.role_id')
.join(`${T.PERMISSIONS} AS p`, 'p.id', 'rp.permission_id')
.where('ur.user_id', '=', userId);
userPermissionQuery = userPermissionQuery.union((db) => {
db.select('project', 'permission', 'environment', 'p.type', 'gr.role_id')
.from(`${T.GROUP_USER} AS gu`)
.join(`${T.GROUPS} AS g`, 'g.id', 'gu.group_id')
.join(`${T.GROUP_ROLE} AS gr`, 'gu.group_id', 'gr.group_id')
.join(`${T.ROLE_PERMISSION} AS rp`, 'rp.role_id', 'gr.role_id')
.join(`${T.PERMISSIONS} AS p`, 'p.id', 'rp.permission_id')
.where('gu.user_id', '=', userId);
});
const rows = await userPermissionQuery;
stopTimer();
return rows.map(this.mapUserPermission);
}
mapUserPermission(row) {
let project = undefined;
// Since the editor should have access to the default project,
// we map the project to the project and environment specific
// permissions that are connected to the editor role.
if (row.type !== constants_1.ROOT_PERMISSION_TYPE) {
project = row.project;
}
const environment = row.type === constants_1.ENVIRONMENT_PERMISSION_TYPE
? row.environment
: undefined;
return {
project,
environment,
permission: row.permission,
};
}
async getPermissionsForRole(roleId) {
const stopTimer = this.timer('getPermissionsForRole');
const rows = await this.db
.select('p.id', 'p.permission', 'rp.environment', 'p.display_name', 'p.type')
.from(`${T.ROLE_PERMISSION} as rp`)
.join(`${T.PERMISSIONS} as p`, 'p.id', 'rp.permission_id')
.where('rp.role_id', '=', roleId);
stopTimer();
return rows.map((permission) => {
return {
id: permission.id,
name: permission.permission,
environment: permission.environment,
displayName: permission.display_name,
type: permission.type,
};
});
}
async addEnvironmentPermissionsToRole(role_id, permissions) {
const rows = permissions.map((permission) => {
return {
role_id,
permission_id: permission.id,
environment: permission.environment,
};
});
await this.db.batchInsert(T.ROLE_PERMISSION, rows);
}
async unlinkUserRoles(userId) {
return this.db(T.ROLE_USER)
.where({
user_id: userId,
})
.delete();
}
async unlinkUserGroups(userId) {
return this.db(T.GROUP_USER)
.where({
user_id: userId,
})
.delete();
}
async clearUserPersonalAccessTokens(userId) {
return this.db(T.PERSONAL_ACCESS_TOKENS)
.where({
user_id: userId,
})
.delete();
}
async clearPublicSignupUserTokens(userId) {
return this.db(T.PUBLIC_SIGNUP_TOKENS_USER)
.where({
user_id: userId,
})
.delete();
}
async getProjectUsersForRole(roleId, projectId) {
const rows = await this.db
.select(['user_id', 'ru.created_at'])
.from(`${T.ROLE_USER} AS ru`)
.join(`${T.ROLES} as r`, 'ru.role_id', 'id')
.where('r.id', roleId)
.andWhere('ru.project', projectId);
return rows.map((r) => ({
userId: r.user_id,
addedAt: r.created_at,
}));
}
async getRolesForUserId(userId) {
return this.db
.select(['id', 'name', 'type', 'project', 'description'])
.from(T.ROLES)
.innerJoin(`${T.ROLE_USER} as ru`, 'ru.role_id', 'id')
.where('ru.user_id', '=', userId);
}
async getUserIdsForRole(roleId) {
const rows = await this.db
.select(['user_id'])
.from(T.ROLE_USER)
.where('role_id', roleId);
return rows.map((r) => r.user_id);
}
async addUserToRole(userId, roleId, projectId) {
return this.db(T.ROLE_USER).insert({
user_id: userId,
role_id: roleId,
project: projectId,
});
}
async removeUserFromRole(userId, roleId, projectId) {
return this.db(T.ROLE_USER)
.where({
user_id: userId,
role_id: roleId,
project: projectId,
})
.delete();
}
async addGroupToRole(groupId, roleId, createdBy, projectId) {
return this.db(T.GROUP_ROLE).insert({
group_id: groupId,
role_id: roleId,
project: projectId,
created_by: createdBy,
});
}
async removeGroupFromRole(groupId, roleId, projectId) {
return this.db(T.GROUP_ROLE)
.where({
group_id: groupId,
role_id: roleId,
project: projectId,
})
.delete();
}
async updateUserProjectRole(userId, roleId, projectId) {
return this.db(T.ROLE_USER)
.where({
user_id: userId,
project: projectId,
})
.whereNotIn('role_id', this.db(T.ROLES).select('id as role_id').where('type', 'root'))
.update('role_id', roleId);
}
updateGroupProjectRole(groupId, roleId, projectId) {
return this.db(T.GROUP_ROLE)
.where({
group_id: groupId,
project: projectId,
})
.whereNotIn('role_id', this.db(T.ROLES).select('id as role_id').where('type', 'root'))
.update('role_id', roleId);
}
async addAccessToProject(users, groups, projectId, roleId, createdBy) {
const userRows = users.map((user) => {
return {
user_id: user.id,
project: projectId,
role_id: roleId,
};
});
const groupRows = groups.map((group) => {
return {
group_id: group.id,
project: projectId,
role_id: roleId,
created_by: createdBy,
};
});
await this.db.transaction(async (tx) => {
if (userRows.length > 0) {
await tx(T.ROLE_USER)
.insert(userRows)
.onConflict(['project', 'role_id', 'user_id'])
.merge();
}
if (groupRows.length > 0) {
await tx(T.GROUP_ROLE)
.insert(groupRows)
.onConflict(['project', 'role_id', 'group_id'])
.merge();
}
});
}
async removeRolesOfTypeForUser(userId, roleType) {
const rolesToRemove = this.db(T.ROLES)
.select('id')
.where({ type: roleType });
return this.db(T.ROLE_USER)
.where({ user_id: userId })
.whereIn('role_id', rolesToRemove)
.delete();
}
async addPermissionsToRole(role_id, permissions, environment) {
const rows = await this.db
.select('id as permissionId')
.from(T.PERMISSIONS)
.whereIn('permission', permissions);
const newRoles = rows.map((row) => ({
role_id,
environment,
permission_id: row.permissionId,
}));
return this.db.batchInsert(T.ROLE_PERMISSION, newRoles);
}
async removePermissionFromRole(role_id, permission, environment) {
const rows = await this.db
.select('id as permissionId')
.from(T.PERMISSIONS)
.where('permission', permission);
const permissionId = rows[0].permissionId;
return this.db(T.ROLE_PERMISSION)
.where({
role_id,
permission_id: permissionId,
environment,
})
.delete();
}
async wipePermissionsFromRole(role_id) {
return this.db(T.ROLE_PERMISSION)
.where({
role_id,
})
.delete();
}
async cloneEnvironmentPermissions(sourceEnvironment, destinationEnvironment) {
return this.db.raw(`insert into role_permission
(role_id, permission_id, environment)
(select role_id, permission_id, ?
from ${T.ROLE_PERMISSION} where environment = ?)`, [destinationEnvironment, sourceEnvironment]);
}
async isChangeRequestsEnabled(project, environment) {
const result = await this.db.raw(`SELECT EXISTS(SELECT 1 FROM ${T.CHANGE_REQUEST_SETTINGS}
WHERE environment = ? and project = ?) AS present`, [environment, project]);
const { present } = result.rows[0];
return present;
}
}
exports.AccessStore = AccessStore;
//# sourceMappingURL=access-store.js.map