This repository has been archived on 2022-11-26. You can view files and clone it, but cannot push or open issues or pull requests.
IcyNet.eu/server/api/oauth2/model.js

295 lines
6.9 KiB
JavaScript

import config from '../../../scripts/load-config'
import * as Models from '../models'
import { User, Login } from '../index'
import crypto from 'crypto'
export const scopes = {
email: ['See your Email address', 'View the user\'s email address'],
image: ['', 'View the user\'s profile picture'],
privilege: ['', 'See the user\'s privilege level']
}
export const accessToken = {
ttl: config.oauth2.access_token_life,
getToken: (object) => {
if (object) return object.token
return null
},
create: async (userId, clientId, scope, ttl) => {
const token = crypto.randomBytes(config.oauth2.token_length).toString('hex')
const expr = new Date(Date.now() + ttl * 1000)
if (typeof scope === 'object') {
scope = scope.join(' ')
}
// Delete already existing tokens with this exact user id, client id and scope, because it will
// eventually pile up and flood the database.
await Models.OAuth2AccessToken.query().delete().where('user_id', userId)
.andWhere('client_id', clientId)
const obj = {
token,
scope,
user_id: userId,
client_id: clientId,
expires_at: expr,
created_at: new Date()
}
const res = await Models.OAuth2AccessToken.query().insert(obj)
if (!res) return null
return res.token
},
fetchByToken: async (token) => {
if (typeof token === 'object') {
return token
}
token = await Models.OAuth2AccessToken.query().where('token', token)
if (!token.length) return null
return token[0]
},
checkTTL: (object) => {
return (object.expires_at > Date.now())
},
getTTL: (object) => {
return (object.expires_at - Date.now())
},
fetchByUserIdClientId: async (userId, clientId) => {
const tkn = await Models.OAuth2AccessToken.query().where('user_id', userId).andWhere('client_id', clientId)
if (!tkn.length) return null
return tkn[0]
}
}
export const client = {
getId: (c) => {
return c.id
},
fetchById: async (id) => {
const c = await Models.OAuth2Client.query().where('id', id)
if (!c.length) return null
return c[0]
},
checkSecret: (c, secret) => {
return c.secret === secret
},
checkGrantType: (c, grant) => {
if (c.grants.indexOf(grant) !== -1) {
return true
}
return false
},
getRedirectUri: (c) => {
return c.redirect_url
},
checkRedirectUri: (c, redirectUri) => {
return (redirectUri.indexOf(client.getRedirectUri(c)) === 0 &&
redirectUri.replace(client.getRedirectUri(c), '').indexOf('#') === -1)
},
transformScope: (scope) => {
if (!scope) return []
if (typeof scope === 'object') {
return scope
}
scope = scope.trim()
if (scope.indexOf(',') !== -1) {
scope = scope.split(',')
} else {
scope = scope.split(' ')
}
return scope
},
checkScope: (c, scope) => {
if (!scope) return []
if (typeof scope === 'string') {
scope = c.transformScope(scope)
}
const clientScopes = c.scope.split(' ')
for (const i in scope) {
if (clientScopes.indexOf(scope[i]) === -1) {
return false
}
}
return scope
}
}
export const code = {
ttl: config.oauth2.code_life,
create: async (userId, clientId, scope, ttl) => {
const newCode = crypto.randomBytes(config.oauth2.token_length).toString('hex')
const expr = new Date(Date.now() + ttl * 1000)
if (typeof scope === 'object') {
scope = scope.join(' ')
}
// Delete already existing codes with this exact user id, client id and scope, because it will
// eventually pile up and flood the database, especially when they were never used.
await Models.OAuth2Code.query().delete().where('user_id', userId).andWhere('client_id', clientId)
const obj = {
code: newCode,
scope,
user_id: userId,
client_id: clientId,
expires_at: expr,
created_at: new Date()
}
await Models.OAuth2Code.query().insert(obj)
return obj.code
},
fetchByCode: async (c) => {
c = await Models.OAuth2Code.query().where('code', c)
if (!c.length) return null
return c[0]
},
removeByCode: async (c) => {
if (typeof c === 'object') {
c = c.code
}
return Models.OAuth2Code.query().delete().where('code', c)
},
getUserId: (c) => {
return c.user_id
},
getClientId: (c) => {
return c.client_id
},
getScope: (c) => {
return c.scope
},
checkTTL: (c) => {
return (c.expires_at > Date.now())
}
}
export const refreshToken = {
create: async (userId, clientId, scope) => {
const token = crypto.randomBytes(config.oauth2.token_length).toString('hex')
if (typeof scope === 'object') {
scope = scope.join(' ')
}
const obj = {
token,
scope,
user_id: userId,
client_id: clientId,
created_at: new Date()
}
await Models.OAuth2RefreshToken.query().insert(obj)
return obj.token
},
fetchByToken: async (token) => {
token = await Models.OAuth2RefreshToken.query().where('token', token)
if (!token.length) return null
return token[0]
},
removeByUserIdClientId: async (userId, clientId) => {
return Models.OAuth2RefreshToken.query().delete().where('user_id', userId)
.andWhere('client_id', clientId)
},
removeByRefreshToken: async (token) => {
return Models.OAuth2RefreshToken.query().delete().where('token', token)
},
getUserId: (t) => {
return t.user_id
},
getClientId: (t) => {
return t.client_id
},
getScope: (t) => {
return t.scope
}
}
export const user = {
getId: (u) => {
return u.id
},
fetchById: User.get,
fetchByUsername: User.get,
checkPassword: Login.password,
fetchFromRequest: async (req) => {
if (!req.session.user) return null
const banStatus = await User.getBanStatus(req.session.user.id)
if (banStatus.length) {
delete req.session.user
return null
}
return req.session.user
},
consented: async (userId, clientId, scope) => {
if (typeof scope === 'object') {
scope = scope.join(' ')
}
const authorized = await Models.OAuth2AuthorizedClient.query().where('user_id', userId)
if (!authorized.length) return false
let correct = false
for (const i in authorized) {
if (authorized[i].client_id === clientId) {
correct = authorized[i]
}
}
if (correct) {
if (correct.scope !== scope) {
await Models.OAuth2AuthorizedClient.query().delete().where('user_id', userId)
.andWhere('client_id', correct.client_id)
return false
}
correct = true
}
return correct
},
consent: async (userId, clientId, scope) => {
if (!config.oauth2.save_decision) return true
if (typeof scope === 'object') {
scope = scope.join(' ')
}
const obj = {
scope,
user_id: userId,
client_id: clientId,
created_at: new Date()
}
await Models.OAuth2AuthorizedClient.query().insert(obj)
return true
}
}