import passport from 'passport' import jwt, { JwtHeader } from 'jsonwebtoken' import fs from 'fs' import jwksClient from 'jwks-rsa' import { CreateTableIfNotExists, TranslateToObject, QueryTable, Query, getEntityGenerator, UpsertTable } from '@feedyou/utils' import allowedUsers from './allowedUsers' import { createAllowedUsersStrategy, createBotTokenStrategy, UserInfo } from './customStrategy' import { getBotById } from './src/data/bots/storageService' import { TableUser, TableDomain } from './src/data/users/types' const client = jwksClient({ // TODO: env file jwksUri: process.env.AUTH0_JWKS_URL }) var _allowedUsers: string[] const ROLES = ['view', 'comment', 'copywrite', 'edit', 'admin'] const USERS_TABLE = 'User' const DOMAINS_TABLE = 'Domain' export function isAuthEnabled() { return process.env.AUTH0_JWKS_URL && process.env.AUTH0_USER_INFO_URL } export function authenticate(providers: string[]) { return passport.authenticate(providers, { session: false }) } export function initPassport() { passport.use('allowed-users', createAllowedUsersStrategy()) return passport.use('bot-token', createBotTokenStrategy()) } export function parseToken(token: string) { if (token && token.includes('Bearer')) { return token.substr(7) } else { return null } } export function decodeToken(token: string) { return new Promise((resolve, reject) => { jwt.verify(token, _getKey, {}, function(err, decoded) { if (err) { reject(err) } resolve(decoded) }) }) } export async function getBotPermissions(id: string) { const bot = await getBotById(id) if (!bot && !bot.bot) { throw new Error('Invalid bot id.') } return bot.bot.permissions || [] } export function checkRole(role: string, minRole: string) { if (role && minRole) { const roleIndex = ROLES.findIndex(_role => _role === role) const minRoleIndex = ROLES.findIndex(_role => _role === minRole) return minRoleIndex <= roleIndex } return false } export async function getAllowedUsers() { return _allowedUsers ? _allowedUsers : await initAllowedUsers() } export async function initAllowedUsers() { const tableUsers = await _getTableUsers() const domainUsers = await _getDomainUsers() _allowedUsers = [...allowedUsers, ...tableUsers, ...domainUsers] console.log('Allowed users: ', _allowedUsers) } async function _getDomainUsers() { await CreateTableIfNotExists(DOMAINS_TABLE) const result = TranslateToObject(await QueryTable(DOMAINS_TABLE, Query())) const domainUsers = result .filter(entry => entry.Role && ROLES.includes(entry.Role)) .map(entry => entry.PartitionKey) || [] return domainUsers } async function _getTableUsers(): Promise { await CreateTableIfNotExists(USERS_TABLE) const result = TranslateToObject( await QueryTable(USERS_TABLE, Query().where('PartitionKey eq ?', 'facebook')) ) const tableUsers = result.filter(entry => entry.Role && ROLES.includes(entry.Role)).map(entry => entry.Email) || [] return tableUsers } function _getKey(header: JwtHeader, callback: Function) { client.getSigningKey(header.kid, function(err, key) { if (!key) { console.error('Key is undefined!', err) callback('Key is undefined!', null) } else { const signingKey = key.publicKey || key.rsaPublicKey if (!signingKey) { console.error('SigningKey is undefined!') callback('SigningKey is undefined!', null) } else { callback(null, signingKey) } } }) } export function logUnauthorized(userInfo: UserInfo) { const { sub, email, name } = userInfo const separatorIndex = sub.indexOf('|') const partitionKey = sub.substr(0, separatorIndex) const rowKey = sub.substr(separatorIndex + 1) fs.appendFile('security.log', '[' + Date.now() + '] ' + email + '\n', () => {}) console.error('This user (' + email + ') is not allowed to access API.') const entityGenerator = getEntityGenerator() const entity = { PartitionKey: entityGenerator.String(partitionKey), RowKey: entityGenerator.String(rowKey), Role: entityGenerator.String('guest'), Email: entityGenerator.String(email), Name: entityGenerator.String(name) } UpsertTable(USERS_TABLE, entity, 'replace').catch(err => { console.error(err) }) }