rework login and make register
This commit is contained in:
@@ -73,15 +73,13 @@ implements RPCExporter<EventbusIfc, "Eventbus">, TableDefinitionExporter {
|
||||
exportRPCs(){
|
||||
return [{
|
||||
name: 'getNotificationLog' as 'getNotificationLog',
|
||||
call: async () => await this.getNotificationLog()
|
||||
call: this.getNotificationLog
|
||||
},{
|
||||
name: 'pushNotification' as 'pushNotification',
|
||||
call: async (notification: Notification) => { return await this.pushNotification(notification) }
|
||||
call: this.pushNotification
|
||||
},{
|
||||
name: 'subscribeNotificaitons' as 'subscribeNotifications',
|
||||
hook: async (callback: Function) => {
|
||||
return await this.subscribeNotifications(callback)
|
||||
}
|
||||
hook: async (callback: Function) => await this.subscribeNotifications(callback)
|
||||
}]
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ implements FrontworkComponent<GuildManagerIfc, GuildManagerFeatureIfc>{
|
||||
|
||||
exportRPCs = () => [{
|
||||
name: 'getHeadCount' as 'getHeadCount',
|
||||
call: async () => await this.headCount()
|
||||
call: this.headCount
|
||||
},{
|
||||
name: 'getGuildInfo' as 'getGuildInfo',
|
||||
call: async () => this.guild.getConfig()
|
||||
|
||||
@@ -29,10 +29,10 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
|
||||
exportRPCs(): RPC<any, any>[]{
|
||||
return [{
|
||||
name: 'getItems',
|
||||
call: async () => await this.getItems()
|
||||
call: this.getItems
|
||||
},{
|
||||
name: 'getItem',
|
||||
call: async (name:string) => await this.getItem(name)
|
||||
call: this.getItem
|
||||
}]
|
||||
}
|
||||
|
||||
|
||||
@@ -146,22 +146,22 @@ implements RPCExporter<PluginLoaderIfc, "PluginLoader">{
|
||||
exportRPCs(){
|
||||
return [{
|
||||
name: "installPlugin" as "installPlugin",
|
||||
call: async (name:string, force = false) => {return await this.installPlugin(name, force)},
|
||||
call: this.installPlugin,
|
||||
},{
|
||||
name: "startPlugin" as "startPlugin",
|
||||
call: async (name:string) => {return await this.startPlugin(name)},
|
||||
call: this.startPlugin,
|
||||
},{
|
||||
name: "updatePlugin" as "updatePlugin",
|
||||
call: async (name:string) => {return await this.updatePlugin(name)},
|
||||
call: this.updatePlugin,
|
||||
},{
|
||||
name: "setPluginVersion" as "setPluginVersion",
|
||||
call: async (name:string, tag:string) => {return await this.setPluginVersion(name, tag)},
|
||||
call: this.setPluginVersion,
|
||||
},{
|
||||
name: "getLoadedPluginNames" as "getLoadedPluginNames",
|
||||
call: async () => {return this.getPlugins().map(p => p.name)},
|
||||
call: async () => this.getPlugins().map(p => p.name),
|
||||
},{
|
||||
name: "selfUpdate" as "selfUpdate",
|
||||
call: async (force: boolean) => {return await this.selfUpdate(force)},
|
||||
call: this.selfUpdate,
|
||||
}]
|
||||
}
|
||||
}
|
||||
@@ -21,22 +21,22 @@ implements RPCExporter<ConfigLoaderIfc<ConfT>, "Config">{
|
||||
exportRPCs() {
|
||||
return [{
|
||||
name: "getConfig" as "getConfig",
|
||||
call: () => { return this.getConfig() }
|
||||
call: this.getConfig
|
||||
},{
|
||||
name: "resetConfig" as "resetConfig",
|
||||
call: () => { return this.resetConfig() }
|
||||
call: this.resetConfig
|
||||
},{
|
||||
name: "setConfig" as "setConfig",
|
||||
call: (conf:ConfT) => { return this.setConfig(conf) }
|
||||
call: this.setConfig
|
||||
},{
|
||||
name: "setConfigKey" as "setConfigKey",
|
||||
call: (key:string, value:any) => { return this.setConfigKey(key, value) }
|
||||
call: this.setConfigKey
|
||||
},{
|
||||
name: "deleteConfigKey" as "deleteConfigKey",
|
||||
call: (key:string) => { return this.deleteConfigKey(key) }
|
||||
call: this.deleteConfigKey
|
||||
},{
|
||||
name: "getConfigKey" as "getConfigKey",
|
||||
call: (key:string) => { return this.getConfigKey(key) }
|
||||
call: this.getConfigKey
|
||||
}]
|
||||
}
|
||||
}
|
||||
@@ -15,25 +15,25 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>{
|
||||
name: 'manageRaid' as 'manageRaid',
|
||||
exportRPCs: () => [{
|
||||
name: 'createRaid' as 'createRaid',
|
||||
call: async (raid:Raid) => await this.createRaid(raid)
|
||||
call: this.createRaid
|
||||
},{
|
||||
name: 'addSignup' as 'addSignup',
|
||||
call: async(signup: Signup) => await this.addSignup(signup)
|
||||
call: this.addSignup
|
||||
},{
|
||||
name: 'removeSignup' as 'removeSignup',
|
||||
call: async(signup: Signup) => await this.removeSignup(signup)
|
||||
call: this.removeSignup
|
||||
}]
|
||||
},{
|
||||
name: 'signup' as 'signup',
|
||||
exportRPCs: () => [{
|
||||
name: 'getRaids' as 'getRaids',
|
||||
call: async () => await this.getRaids()
|
||||
call: this.getRaids
|
||||
},{
|
||||
name: 'getSingups' as 'getSingups',
|
||||
call: async(raid: Raid) => await this.getSignups(raid)
|
||||
call: this.getSignups
|
||||
},{
|
||||
name: 'sign' as 'sign',
|
||||
call: async(user:User, raid:Raid) => await this.sign(user, raid)
|
||||
call: this.sign
|
||||
}]
|
||||
},]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,291 @@
|
||||
import { RPCServer, Socket } from "rpclibrary";
|
||||
import { TableDefiniton, AnyRPCExporter, User, RPCPermission, Token, Auth, Rank, FrontcraftFeatureIfc, _Rank } from "../../Types/Types";
|
||||
import { FrontworkAdmin } from "../../Admin/Admin";
|
||||
import { PrivilegedRPCExporter } from "../../Types/PrivilegedRPCExporter";
|
||||
import { FrontworkComponent } from "../../Types/FrontworkComponent";
|
||||
import { getSpecTableData } from "../../Types/PlayerSpecs"
|
||||
import { LoginManagerIfc, LoginManagerFeatureIfc } from "./RPCInterface";
|
||||
const uuid = require('uuid/v4')
|
||||
|
||||
const ONE_WEEK = 604800000
|
||||
|
||||
type Serverstate = {
|
||||
server: RPCServer,
|
||||
port : number,
|
||||
allowed: string[]
|
||||
}
|
||||
|
||||
export class LoginManager
|
||||
implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>{
|
||||
name = "Authenticator" as "Authenticator";
|
||||
admin:FrontworkAdmin
|
||||
|
||||
rankServers : {[rank in Rank] : Serverstate}
|
||||
userLogins : {[username in string] : {
|
||||
connections: {[port in number]: Socket}
|
||||
auth: Auth
|
||||
}} = {}
|
||||
|
||||
constructor(
|
||||
private exporters: PrivilegedRPCExporter[]
|
||||
){}
|
||||
|
||||
exportRPCs = () => [
|
||||
{
|
||||
name: 'login' as 'login',
|
||||
call: this.login
|
||||
},{
|
||||
name: 'logout' as 'logout',
|
||||
call: this.logout
|
||||
},{
|
||||
name: 'getAuth' as 'getAuth',
|
||||
call: this.getAuth
|
||||
},{
|
||||
name: 'checkToken' as 'checkToken',
|
||||
call: async (tokenValue : string, rank: Rank) => this.checkToken(tokenValue, rank)
|
||||
}
|
||||
]
|
||||
|
||||
onSetAdmin(admin:FrontworkAdmin){
|
||||
this.exporters.forEach(e => e['admin'] = admin)
|
||||
}
|
||||
|
||||
exportRPCFeatures = () => [
|
||||
{
|
||||
name: 'createUser' as 'createUser',
|
||||
exportRPCs: () => [{
|
||||
name: 'createUser' as 'createUser',
|
||||
call: this.createUser
|
||||
}]
|
||||
},{
|
||||
name: 'modifyPermissions' as 'modifyPermissions',
|
||||
exportRPCs: () => [{
|
||||
name: 'getPermissions' as 'getPermissions',
|
||||
call: this.getPermissions
|
||||
},{
|
||||
name: 'setPermission' as 'setPermission',
|
||||
call: this.setPermission
|
||||
}]
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
getTableDefinitions = (): TableDefiniton[] => [
|
||||
{
|
||||
name: 'users',
|
||||
tableBuilder: (table) => {
|
||||
table.increments("id").primary()
|
||||
table.string("name").notNullable().unique()
|
||||
table.string("pwhash").notNullable()
|
||||
table.string("rank").notNullable()
|
||||
table.string("email").nullable().unique()
|
||||
}
|
||||
},{
|
||||
name: 'characters',
|
||||
tableBuilder: (table) => {
|
||||
table.increments("id").primary()
|
||||
table.string("name").notNullable().unique()
|
||||
table.integer("specid").notNullable()
|
||||
table.foreign("specid").references("specs.id")
|
||||
table.integer("userid").notNullable()
|
||||
table.foreign("userid").references("users.id")
|
||||
}
|
||||
},{
|
||||
name: 'rpcpermissions',
|
||||
tableBuilder: (table) => {
|
||||
table.string("name").primary().notNullable()
|
||||
table.boolean("ADMIN").defaultTo(true).notNullable()
|
||||
_Rank.forEach(r => table.boolean(r).defaultTo(false).notNullable())
|
||||
}
|
||||
},{
|
||||
name: 'specs',
|
||||
tableBuilder: (table) => {
|
||||
table.increments("id")
|
||||
table.string('class')
|
||||
table.string('name')
|
||||
}
|
||||
}
|
||||
,...this.exporters.flatMap(exp => exp['getTableDefinitions']?exp['getTableDefinitions']():undefined)
|
||||
]
|
||||
|
||||
initialize = async () => {
|
||||
//set up permissions
|
||||
await Promise.all(
|
||||
[this, ...this.exporters].flatMap(exp => exp.exportRPCFeatures().map(async (feature) => {
|
||||
try{
|
||||
await this.admin.knex.insert({ name: feature.name }).into('rpcpermissions')
|
||||
}catch(e){}
|
||||
})))
|
||||
|
||||
//initialize managed exporters
|
||||
await Promise.all(this.exporters.map(ex => ex['initialize']?ex['initialize']():undefined))
|
||||
|
||||
//initialize spec table
|
||||
await this.admin.knex('specs').insert(getSpecTableData()).catch(e => { console.log("skipping spec insertion") })
|
||||
|
||||
//start rankServers
|
||||
const rankServers : any = {}
|
||||
|
||||
for(let i = 0; i < _Rank.length; i++){
|
||||
const rank:Rank = _Rank[i]
|
||||
const port = 20001 + i
|
||||
const rankServer = await this.startRankServer(rank, port)
|
||||
rankServers[rank] = {
|
||||
server: rankServer,
|
||||
port: port,
|
||||
allowed: []
|
||||
}
|
||||
}
|
||||
this.rankServers = rankServers
|
||||
|
||||
setInterval(this.checkExpiredSessions, 600_000)
|
||||
}
|
||||
|
||||
checkExpiredSessions = () => {
|
||||
Object.values(this.userLogins).map(userLogin => {
|
||||
const auth = userLogin.auth
|
||||
if(!this.checkToken(auth.token.value, auth.user.rank)){
|
||||
this.logout(auth.user.name, auth.token.value)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
checkConnection = async (socket: Socket) => {
|
||||
let data : Auth | false = false
|
||||
while(!data){
|
||||
data = await Promise.race([socket.call('getUserData'), new Promise((res, rej) => { setTimeout(res, 250);})])
|
||||
}
|
||||
this.userLogins[data.user.name].connections[socket.port] = socket
|
||||
await socket.call('navigate', ["/frontcraft/dashboard"])
|
||||
return true
|
||||
}
|
||||
|
||||
setPermission = async (permission: RPCPermission) => {
|
||||
await this.admin.knex('rpcpermissions')
|
||||
.where('rpcname', '=', permission.name)
|
||||
.update(permission)
|
||||
}
|
||||
|
||||
getPermissions = async () : Promise<RPCPermission[]> => {
|
||||
return await this.admin.knex.select('*').from('rpcpermissions')
|
||||
}
|
||||
|
||||
getPermission = async (feature: keyof FrontcraftFeatureIfc, rank:Rank) : Promise<boolean> => {
|
||||
const perm : RPCPermission[] = await this.admin.knex
|
||||
.select(rank)
|
||||
.from('rpcpermissions')
|
||||
.where('name', '=', <string>feature)
|
||||
|
||||
if(perm.length === 0) return false
|
||||
return perm[0][rank]
|
||||
}
|
||||
|
||||
getRPCForRank = async (rank: Rank): Promise<AnyRPCExporter[]> => {
|
||||
return [
|
||||
...this.exportRPCFeatures(),
|
||||
...this.exporters.flatMap((exp) => exp.exportRPCFeatures())
|
||||
].filter(async (feature) => await this.getPermission(<keyof FrontcraftFeatureIfc> feature.name, rank))
|
||||
}
|
||||
|
||||
createUser = async(user:User): Promise<User> => {
|
||||
await this.admin.knex('users')
|
||||
.insert(user)
|
||||
|
||||
const users = await this.admin.knex
|
||||
.select("*")
|
||||
.from('users')
|
||||
.where(user)
|
||||
return users[0]
|
||||
}
|
||||
|
||||
logout = async (username:string, tokenValue : string) : Promise<void> => {
|
||||
try{
|
||||
|
||||
await Promise.all (Object.values(this.userLogins[username].connections).map(async (sock) => {
|
||||
await sock.call('navigate', '/auth/login')
|
||||
}))
|
||||
|
||||
Object.values(this.rankServers)
|
||||
.forEach(state => {
|
||||
state.allowed = state.allowed.filter(allowed => allowed !== tokenValue)
|
||||
})
|
||||
|
||||
delete this.userLogins[username]
|
||||
}catch(e){
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
|
||||
login = async(username:string, pwHash:string) : Promise<Auth> => {
|
||||
const res:User[] = await this.admin.knex
|
||||
.select('*')
|
||||
.from('users')
|
||||
.where({ name: username })
|
||||
|
||||
if(res.length > 0 && pwHash === res[0].pwhash){
|
||||
const user:User = res[0]
|
||||
delete user.pwhash
|
||||
|
||||
//return existing auth
|
||||
if(this.userLogins[username] != null){
|
||||
return this.userLogins[username].auth
|
||||
}
|
||||
|
||||
const token = this.createToken(user)
|
||||
const userAuth : Auth = {
|
||||
token: token,
|
||||
user: user,
|
||||
port: this.rankServers[user.rank].port
|
||||
}
|
||||
|
||||
this.userLogins[user.name] = {connections: {}, auth: userAuth}
|
||||
this.rankServers[user.rank].allowed.push(token.value)
|
||||
|
||||
return userAuth
|
||||
}
|
||||
|
||||
throw new Error('login failed')
|
||||
}
|
||||
|
||||
getAuth = async (tokenValue:string) : Promise<Auth> => {
|
||||
const maybeAuth = Object.values(this.userLogins).find(login => login.auth.token.value === tokenValue)
|
||||
if(maybeAuth)
|
||||
return maybeAuth.auth
|
||||
|
||||
throw new Error("Bad token")
|
||||
}
|
||||
|
||||
startRankServer = async (rank : Rank, port: number) : Promise<RPCServer> => {
|
||||
const allowedRPCs = await this.getRPCForRank(rank)
|
||||
let rpcServer : RPCServer = new RPCServer(port, allowedRPCs, {
|
||||
closeHandler: (socket) => {
|
||||
Object.values(this.userLogins)
|
||||
.forEach(login => delete login.connections[socket.port])
|
||||
|
||||
},
|
||||
connectionHandler: (socket) => {
|
||||
this.checkConnection(socket).catch(() => {}) //sometimes times out if you go too fast
|
||||
},
|
||||
sesame: (sesame) => this.checkToken(sesame, rank)
|
||||
})
|
||||
return rpcServer
|
||||
}
|
||||
|
||||
checkToken = (token: string, rank: Rank) : boolean => this.rankServers[rank].allowed.includes(token)
|
||||
&& Object.values(this.userLogins).find(login => login.auth.token.value === token)!.auth.token.created > Date.now() - ONE_WEEK
|
||||
|
||||
createToken = (user:User): Token => {
|
||||
|
||||
if(this.userLogins[user.name]){
|
||||
return this.userLogins[user.name].auth.token
|
||||
}
|
||||
|
||||
const token:Token = {
|
||||
value: uuid(),
|
||||
user_id: user.id!,
|
||||
created: Date.now()
|
||||
}
|
||||
|
||||
return token
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,15 @@
|
||||
import { Token, Auth, User, RPCPermission } from "../../Types/Types"
|
||||
import { Token, Auth, User, RPCPermission, Rank } from "../../Types/Types"
|
||||
|
||||
export type UserManagerIfc = {
|
||||
export type LoginManagerIfc = {
|
||||
Authenticator: {
|
||||
login: (username:string, pwHash:string) => Promise<Token>
|
||||
authenticate: (token:string | Token) => Promise<Auth>
|
||||
login: (username:string, pwHash:string) => Promise<Auth>
|
||||
logout: (username: string, tokenValue :string) => Promise<void>
|
||||
getAuth: (tokenValue: string) => Promise<Auth>
|
||||
checkToken: (token: string, rank: Rank) => Promise<boolean>
|
||||
}
|
||||
}
|
||||
|
||||
export type UserManagerFeatureIfc = {
|
||||
export type LoginManagerFeatureIfc = {
|
||||
createUser: {
|
||||
createUser: (user:User) => Promise<User>
|
||||
}
|
||||
|
||||
@@ -1,227 +0,0 @@
|
||||
import { RPCServer } from "rpclibrary";
|
||||
import { TableDefiniton, AnyRPCExporter, User, RPCPermission, _Rank, Token, Auth, Rank, FrontcraftFeatureIfc } from "../../Types/Types";
|
||||
import { FrontworkAdmin } from "../../Admin/Admin";
|
||||
import { PrivilegedRPCExporter } from "../../Types/PrivilegedRPCExporter";
|
||||
import { FrontworkComponent } from "../../Types/FrontworkComponent";
|
||||
import { getSpecTableData } from "../../Types/PlayerSpecs"
|
||||
import { UserManagerIfc, UserManagerFeatureIfc } from "./RPCInterface";
|
||||
const uuid = require('uuid/v4')
|
||||
|
||||
export class LoginManager
|
||||
implements FrontworkComponent<UserManagerIfc, UserManagerFeatureIfc>{
|
||||
name = "Authenticator" as "Authenticator";
|
||||
admin:FrontworkAdmin
|
||||
|
||||
constructor(
|
||||
private exporters: PrivilegedRPCExporter[]
|
||||
){}
|
||||
|
||||
exportRPCs = () => [
|
||||
{
|
||||
name: 'login' as 'login',
|
||||
call: async (username:string, pwHash:string) => await this.login(username, pwHash)
|
||||
},{
|
||||
name: 'authenticate' as 'authenticate',
|
||||
call: async (tokenValue:string | Token) => await this.authenticate(tokenValue)
|
||||
}
|
||||
]
|
||||
|
||||
onSetAdmin(admin:FrontworkAdmin){
|
||||
this.exporters.forEach(e => e['admin'] = admin)
|
||||
}
|
||||
|
||||
exportRPCFeatures = () => [
|
||||
{
|
||||
name: 'createUser' as 'createUser',
|
||||
exportRPCs: () => [{
|
||||
name: 'createUser' as 'createUser',
|
||||
call: async (user:User) => await this.createUser(user)
|
||||
}]
|
||||
},{
|
||||
name: 'modifyPermissions' as 'modifyPermissions',
|
||||
exportRPCs: () => [{
|
||||
name: 'getPermissions' as 'getPermissions',
|
||||
call: async () => await this.getPermissions()
|
||||
},{
|
||||
name: 'setPermission' as 'setPermission',
|
||||
call: async (perm: RPCPermission) => await this.setPermission(perm)
|
||||
}]
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
getTableDefinitions = (): TableDefiniton[] => [
|
||||
{
|
||||
name: 'users',
|
||||
tableBuilder: (table) => {
|
||||
table.increments("id").primary()
|
||||
table.string("name").notNullable().unique()
|
||||
table.string("pwhash").notNullable()
|
||||
table.string("rank").notNullable()
|
||||
table.string("email").nullable().unique()
|
||||
}
|
||||
},{
|
||||
name: 'characters',
|
||||
tableBuilder: (table) => {
|
||||
table.increments("id").primary()
|
||||
table.string("name").notNullable().unique()
|
||||
table.integer("specid").notNullable()
|
||||
table.foreign("specid").references("specs.id")
|
||||
table.integer("userid").notNullable()
|
||||
table.foreign("userid").references("users.id")
|
||||
}
|
||||
},{
|
||||
name: 'rpcpermissions',
|
||||
tableBuilder: (table) => {
|
||||
table.string("name").primary().notNullable()
|
||||
table.boolean("ADMIN").defaultTo(true).notNullable()
|
||||
_Rank.forEach(r => table.boolean(r).defaultTo(false).notNullable())
|
||||
}
|
||||
},{
|
||||
name: 'tokens',
|
||||
tableBuilder: (table) => {
|
||||
table.string('value').primary()
|
||||
table.integer('user_id').notNullable()
|
||||
table.foreign('user_id').references('users')
|
||||
table.dateTime('created').defaultTo(this.admin.knex.fn.now())
|
||||
}
|
||||
},{
|
||||
name: 'specs',
|
||||
tableBuilder: (table) => {
|
||||
table.string('class')
|
||||
table.string('name')
|
||||
table.primary(['class', 'name'])
|
||||
}
|
||||
}
|
||||
,...this.exporters.flatMap(exp => exp['getTableDefinitions']?exp['getTableDefinitions']():undefined)
|
||||
]
|
||||
|
||||
|
||||
async initialize(){
|
||||
await Promise.all(
|
||||
[this, ...this.exporters].flatMap(exp => exp.exportRPCFeatures().map(async (feature) => {
|
||||
try{
|
||||
await this.admin.knex.insert({ name: feature.name }).into('rpcpermissions')
|
||||
}catch(e){}
|
||||
})))
|
||||
|
||||
await Promise.all(this.exporters.map(ex => ex['initialize']?ex['initialize']():undefined))
|
||||
|
||||
await this.admin.knex('specs').insert(getSpecTableData()).catch(e => { console.log("skipping spec insertion") })
|
||||
}
|
||||
|
||||
async setPermission(permission: RPCPermission){
|
||||
await this.admin.knex('rpcpermissions')
|
||||
.where('rpcname', '=', permission.name)
|
||||
.update(permission)
|
||||
}
|
||||
|
||||
getPermissions = async () : Promise<RPCPermission[]> => {
|
||||
return await this.admin.knex.select('*').from('rpcpermissions')
|
||||
}
|
||||
|
||||
getPermission = async (feature: keyof FrontcraftFeatureIfc, rank:Rank) : Promise<boolean> => {
|
||||
const perm : RPCPermission[] = await this.admin.knex
|
||||
.select(rank)
|
||||
.from('rpcpermissions')
|
||||
.where('name', '=', <string>feature)
|
||||
|
||||
if(perm.length === 0) return false
|
||||
return perm[0][rank]
|
||||
}
|
||||
|
||||
getRPCForUser = async (user:User): Promise<AnyRPCExporter[]> => {
|
||||
return [
|
||||
...this.exportRPCFeatures(),
|
||||
...this.exporters.flatMap((exp) => exp.exportRPCFeatures())
|
||||
].filter(async (feature) => await this.getPermission(<keyof FrontcraftFeatureIfc> feature.name, user.rank))
|
||||
}
|
||||
|
||||
createUser = async(user:User): Promise<User> => {
|
||||
await this.admin.knex('users')
|
||||
.insert(user)
|
||||
|
||||
const users = await this.admin.knex
|
||||
.select("*")
|
||||
.from('users')
|
||||
.where(user)
|
||||
return users[0]
|
||||
}
|
||||
|
||||
login = async(username:string, pwHash:string) : Promise<Token> => {
|
||||
const res:User[] = await this.admin.knex
|
||||
.select("*")
|
||||
.from('users')
|
||||
.where({ name: username })
|
||||
|
||||
if(res.length > 0 && pwHash === res[0].pwhash){
|
||||
return await this.createToken(res[0])
|
||||
}
|
||||
|
||||
throw new Error('login failed')
|
||||
}
|
||||
|
||||
authenticate = async(tokenValue: string | Token) : Promise<Auth> => {
|
||||
if(typeof tokenValue !== 'string') tokenValue = tokenValue.value
|
||||
|
||||
const res : User[] = await this.admin.knex
|
||||
.select('users.id', 'name', 'specid', 'rank', 'email')
|
||||
.from('tokens')
|
||||
.join('users', function(){
|
||||
this.on('users.id', '=', 'tokens.user_id')
|
||||
})
|
||||
.where({ value: tokenValue})
|
||||
|
||||
if(res.length === 0)
|
||||
throw new Error('authentication failed')
|
||||
|
||||
const allowedRPCs = await this.getRPCForUser(res[0])
|
||||
const randomPort = 20000 + Math.floor(Math.random() * 10000)
|
||||
while(true){
|
||||
try{
|
||||
let commSock = new RPCServer(randomPort, allowedRPCs, {
|
||||
closeHandler: () => {
|
||||
console.log(res[0].name, 'disconnected')
|
||||
commSock.destroy()
|
||||
},
|
||||
connectionHandler: () => {
|
||||
console.log(res[0].name, 'connected')
|
||||
cancelTimeout()
|
||||
},
|
||||
sesame: tokenValue
|
||||
})
|
||||
const timeout = setTimeout(() => {
|
||||
console.log(res[0].name, 'timeout')
|
||||
commSock.destroy()
|
||||
}, 10000)
|
||||
const cancelTimeout = () => { clearTimeout(timeout) }
|
||||
break;
|
||||
}catch(e){
|
||||
//retry
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
port: randomPort,
|
||||
user: res[0],
|
||||
token: {
|
||||
value: tokenValue,
|
||||
user_id: res[0].id!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createToken = async(user:User): Promise<Token> => {
|
||||
const old = await this.admin.knex.select('*').from('tokens').where({user_id: user.id})
|
||||
if(old.length === 0){
|
||||
const token:Token = {
|
||||
value: uuid(),
|
||||
user_id: user.id!
|
||||
}
|
||||
await this.admin.knex('tokens').insert(token)
|
||||
return token
|
||||
}else{
|
||||
return old[0]
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user