changepermissions & 1 rankserver

This commit is contained in:
peter
2020-03-05 20:36:19 +01:00
parent 26dbf8312b
commit c4ca96fef9
15 changed files with 262 additions and 94 deletions
+3 -3
View File
@@ -6130,9 +6130,9 @@
}
},
"rpclibrary": {
"version": "1.8.3",
"resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.8.3.tgz",
"integrity": "sha512-8pQRbMXQKCf3+v+XM01d+1Bw73pg5YzgyhW/ACpYON1I4re5fZAjWGPyLc+ms+MlYQIlKc3Uk92PGot2sbb85Q==",
"version": "1.9.2",
"resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.9.2.tgz",
"integrity": "sha512-MOtVm0IBRLryXag1IwkYNPVFegbvW10+MbCjhr3GptO3MA7nHZ545ammgoCWnREtGOgFeN4Jib/EBDOJ9Ep41Q==",
"requires": {
"bsock": "^0.1.9",
"http": "0.0.0",
+1 -1
View File
@@ -45,7 +45,7 @@
"path": "^0.12.7",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.0",
"rpclibrary": "^1.8.3",
"rpclibrary": "^1.9.2",
"simple-git": "^1.124.0",
"spawn-sync": "^2.0.0",
"sqlite3": "^4.1.1",
+60 -75
View File
@@ -1,4 +1,4 @@
import { RPCServer, Socket } from "rpclibrary";
import { RPCServer, Socket, RPCInterface } from "rpclibrary";
import { Inject, Injectable } from "../../Injector/ServiceDecorator";
import { FrontworkAdmin } from "../../Admin/Admin";
import { GuildManager } from "../Guild/GuildManager";
@@ -23,10 +23,9 @@ const uuid = require('uuid/v4')
const salt = "6pIbc6yjSN"
const ONE_WEEK = 604800000
type Serverstate = {
server: RPCServer,
type Serverstate<SubresT, InterfaceT extends RPCInterface> = {
server: RPCServer<SubresT, InterfaceT>,
port : number,
allowed: string[]
};
@@ -51,8 +50,9 @@ implements FrontworkComponent<UserManagerIfc, UserManagerFeatureIfc>, IUserManag
private character : CharacterManager
exporters :any[] = []
rankServers : {[rank in Rank] : Serverstate}
rankServer : Serverstate<{}, FrontcraftFeatureIfc>
userLogins : {[username in string] : UserRecord} = {}
allowed: string[] = []
exportRPCs = () => [
this.login,
@@ -145,19 +145,11 @@ implements FrontworkComponent<UserManagerIfc, UserManagerFeatureIfc>, IUserManag
}
})))
//start rankServers
let rankServers = { } as any
await Promise.all(_Rank.map(async (r,i) => {
const port = 20001 + i
const rankServer = await this.startRankServer(r, port)
rankServers[r] = {
server: rankServer,
port: port,
allowed: []
}
}))
this.rankServers = rankServers
getLogger('UserManager').debug(Object.values(this.rankServers).length+" rank servers started")
const rankServer = await this.startRankServer(20001)
this.rankServer = {
server: rankServer,
port: 20001
}
setInterval(this.checkExpiredSessions, 600_000)
}
@@ -166,20 +158,17 @@ implements FrontworkComponent<UserManagerIfc, UserManagerFeatureIfc>, IUserManag
Object.values(x.connections).forEach(c => c.destroy())
})
Object.values(this.rankServers)
.map(state => {
try{
return state.server.destroy()
}catch(e){
getLogger('UserManager').warn(e)
}
})
try{
return this.rankServer.server.destroy()
}catch(e){
//getLogger('UserManager').warn(e)
}
}
checkExpiredSessions = () => {
Object.values(this.userLogins).map(userLogin => {
const auth = userLogin.auth
if(!this.checkToken(auth.token.value, auth.user.rank)){
if(!this.checkToken(auth.token.value)){
this.logout(auth.user.username, auth.token.value)
}
})
@@ -232,6 +221,13 @@ implements FrontworkComponent<UserManagerIfc, UserManagerFeatureIfc>, IUserManag
await this.admin.knex('rpcpermissions')
.where('rpcname', '=', permission.rpcname)
.update(permission)
await Promise.all(
Object.entries(this.userLogins).map(([username, record]) => {
if(record.user.rank === "ADMIN") return
return this.adminLogout(username)
})
)
}
getPermissions = async () : Promise<RPCPermission[]> => {
@@ -313,15 +309,10 @@ implements FrontworkComponent<UserManagerIfc, UserManagerFeatureIfc>, IUserManag
await sock.call('kick')
}))
Object.values(this.rankServers)
.forEach(state => {
state.allowed = state.allowed.filter(allowed => allowed !== this.userLogins[username].auth.token.value)
})
this.allowed = this.allowed.filter(allowed => allowed !== this.userLogins[username].auth.token.value)
delete this.userLogins[username]
}
}catch(e){
getLogger('UserManager').warn(e)
}
}catch(e){}
}
wipeCurrency = async () => {
@@ -356,11 +347,11 @@ implements FrontworkComponent<UserManagerIfc, UserManagerFeatureIfc>, IUserManag
const userAuth : Auth = {
token: token,
user: user,
port: this.rankServers[user.rank].port
port: this.rankServer.port
}
this.userLogins[user.username] = {connections: {}, auth: userAuth, user:user}
this.rankServers[user.rank].allowed.push(token.value)
this.allowed.push(token.value)
return userAuth
}
@@ -378,49 +369,43 @@ implements FrontworkComponent<UserManagerIfc, UserManagerFeatureIfc>, IUserManag
return
}
startRankServer = async (rank : Rank, port: number) : Promise<RPCServer> => {
startRankServer = async (port: number) : Promise<RPCServer<{},FrontcraftFeatureIfc>> => {
let rpcs = [
...this.exportRPCFeatures(),
...this.exporters.flatMap((exp) => exp.exportRPCFeatures())
]
let rpcServer = new RPCServer<{},FrontcraftFeatureIfc>(port, rpcs, {
accessFilter: async (sesame, exporter) => {
const record = this.getUserRecordByToken(sesame!)
if(!record) return false
return await this.getPermission(exporter.name, record.user.rank)
},
closeHandler: (socket) => {
Object.values(this.userLogins)
.forEach(login => delete login.connections[socket.port])
},
connectionHandler: (socket) => {
this.checkConnection(socket).then(res => {
if(!res){
socket.destroy();
}
}).catch((e) => {
socket.destroy();
})
},
errorHandler: (socket, e, rpcName, args) => {
getLogger('UserManager').error(rpcName, args, e);
},
sesame: (sesame) => this.checkToken(sesame),
visibility: '0.0.0.0'
})
const allowedRPCs = await this.getRPCForRank(rank)
let rpcServer
let n = 0
while(!rpcServer){
n++
await Promise.race([
new Promise((res, rej) => {
rpcServer = new RPCServer(port, allowedRPCs, {
closeHandler: (socket) => {
Object.values(this.userLogins)
.forEach(login => delete login.connections[socket.port])
},
connectionHandler: (socket) => {
this.checkConnection(socket).then(res => {
if(!res){
socket.destroy();
}
}).catch((e) => {
socket.destroy();
getLogger('UserManager').warn(e);
})
},
errorHandler: (socket, e, rpcName, args) => {
getLogger('UserManager').error(rpcName, args, e);
},
sesame: (sesame) => this.checkToken(sesame, rank),
visibility: '0.0.0.0'
})
res()
}),
new Promise((res, rej) => setTimeout(res, 500))
])
if(!rpcServer && n>1)
getLogger('UserManager').warn("createServer retry nr.", n, 'port', port)
}
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
checkToken = (token: string) : boolean => this.allowed.includes(token)
&& Object.values(this.userLogins).find(login => login.auth.token.value === token)!.auth.token.created > Date.now() - ONE_WEEK
checkTokenOwnedByUser = (username: string, tokenValue: string) => {
username = username.toLowerCase()
+3 -3
View File
@@ -17940,9 +17940,9 @@
"integrity": "sha512-ZYzRkETgBrdEGzL5JSKimvjI2CX7ioyZCkX2BpcfyjqI+079W0wHAyj5W4rIZMcDSOHgLZtgz1IdDi/vU77KEQ=="
},
"rpclibrary": {
"version": "1.8.3",
"resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.8.3.tgz",
"integrity": "sha512-8pQRbMXQKCf3+v+XM01d+1Bw73pg5YzgyhW/ACpYON1I4re5fZAjWGPyLc+ms+MlYQIlKc3Uk92PGot2sbb85Q==",
"version": "1.9.2",
"resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.9.2.tgz",
"integrity": "sha512-MOtVm0IBRLryXag1IwkYNPVFegbvW10+MbCjhr3GptO3MA7nHZ545ammgoCWnREtGOgFeN4Jib/EBDOJ9Ep41Q==",
"requires": {
"bsock": "^0.1.9",
"http": "0.0.0",
+1 -1
View File
@@ -69,7 +69,7 @@
"normalize.css": "6.0.0",
"pace-js": "1.0.2",
"roboto-fontface": "0.8.0",
"rpclibrary": "^1.8.3",
"rpclibrary": "^1.9.2",
"rxjs": "6.5.2",
"rxjs-compat": "6.3.0",
"socicon": "3.0.5",
@@ -9,7 +9,11 @@
<div class="header-container">
<nb-actions size="small">
<nb-action
*ngIf="modifyPermissions"
icon="settings-2-outline"
link="/permissions">
</nb-action>
<nb-action
*ngIf="!newmessage"
icon="message-square-outline"
@@ -48,6 +48,7 @@ export class HeaderComponent implements OnInit, OnDestroy {
chatlog: ShoutMessage[] = []
newmessage = false
lastmessage = "asdasd"
modifyPermissions
constructor(private sidebarService: NbSidebarService,
private router: Router,
@@ -62,7 +63,7 @@ export class HeaderComponent implements OnInit, OnDestroy {
this.themeService.changeTheme("dark");
this.currentTheme = this.themeService.currentTheme;
this.modifyPermissions = this.api.get('modifyPermissions')
this.user = this.api.getCurrentUser()
if(this.user)
this.userMenu.unshift({ title: 'Profile', link: '/frontcraft/user/'+this.user.username });
+5 -1
View File
@@ -2,7 +2,11 @@ import { ExtraOptions, RouterModule, Routes } from '@angular/router';
import { NgModule } from '@angular/core';
const routes: Routes = [
{
path: 'permissions',
loadChildren: () => import('./frontcraft/permissions/permissions.module')
.then(m => m.PermissionsModule),
},
{
path: 'auth',
loadChildren: () => import('./frontcraft/auth/auth.module')
@@ -0,0 +1,23 @@
<nb-card>
<nb-card-body>
<table>
<tr>
<th>
Name
</th>
<th *ngFor="let rank of ranks">
{{rank}}
</th>
</tr>
<tr *ngFor="let perm of permissions">
<td>{{perm.rpcname}}</td>
<td *ngFor="let rank of ranks">
<nb-toggle
[(ngModel)]="perm[rank]"
(checkedChange)="settingChanged($event, rank, perm)">
</nb-toggle>
</td>
</tr>
</table>
</nb-card-body>
</nb-card>
@@ -0,0 +1,43 @@
import { Component, OnInit } from '@angular/core';
import { ApiService as ApiService } from '../../services/login-api';
import { Router } from '@angular/router';
import { _Rank, _Class, _Race, RPCPermission } from '../../../../../../backend/Types/Types'
import { NbToastrService } from '@nebular/theme';
@Component({
selector: 'changePermissions',
templateUrl: './changePermissions.component.html',
})
export class ChangePermissionsComponent implements OnInit{
permissions:RPCPermission[] = []
ranks = _Rank
constructor(
private router : Router,
private api : ApiService,
private toastr: NbToastrService
){}
async ngOnInit(){
const modify = this.api.get('modifyPermissions')
if(!modify) return
this.permissions = await modify.getPermissions()
}
settingChanged = async (value, key, perm:RPCPermission) => {
const modify = this.api.get('modifyPermissions')
if(!modify) return
perm[key] = value
console.log(perm);
await modify.setPermission(perm).catch(e => {
})
this.toastr.success('Permission updated', 'Success')
}
}
@@ -0,0 +1,22 @@
import { Component, OnInit } from '@angular/core';
import { ApiService } from '../services/login-api';
import { Router } from '@angular/router';
@Component({
selector: 'auth-layout',
template: `
<ngx-one-column-no-sidebar-layout>
<router-outlet></router-outlet>
</ngx-one-column-no-sidebar-layout>
`,
})
export class PermissionsComponent implements OnInit{
constructor(
private loginSvc : ApiService,
private router: Router
){}
ngOnInit(){
}
}
@@ -0,0 +1,24 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { PermissionsComponent } from './permissions-layout.component';
import { ChangePermissionsComponent } from './changePermissions/changePermissions.component';
export const routes: Routes = [
{
path: '',
component: PermissionsComponent,
children: [
{
path: '**',
component: ChangePermissionsComponent,
},
]
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class PermissionsRoutingModule {
}
@@ -0,0 +1,43 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import {
NbAlertModule,
NbButtonModule,
NbCheckboxModule,
NbInputModule,
NbMenuModule,
NbCardModule,
NbSelectModule,
NbToggleModule
} from '@nebular/theme';
import { PermissionsComponent } from './permissions-layout.component';
import { ThemeModule } from '../../@theme/theme.module';
import { PermissionsRoutingModule } from './permissions-routing.module';
import { ChangePermissionsComponent } from './changePermissions/changePermissions.component';
@NgModule({
imports: [
NbToggleModule,
PermissionsRoutingModule,
CommonModule,
FormsModule,
RouterModule,
NbAlertModule,
NbInputModule,
NbButtonModule,
NbCheckboxModule,
ThemeModule,
NbMenuModule,
NbCardModule,
NbSelectModule
],
declarations: [
PermissionsComponent,
ChangePermissionsComponent,
],
})
export class PermissionsModule {
}
@@ -34,7 +34,7 @@ export class ApiService{
)
sock.hook('kick', () => {
this.logout()
this.kick()
})
sock.hook('getUserData', () => auth)
@@ -110,6 +110,11 @@ export class ApiService{
return async (msg: ShoutMessage) => await this.get('Shoutbox').shout(res.uuid, msg)
}
kick = async () => {
await this.logout()
location.reload()
}
logout = async () => {
this.cookieSvc.set('token', undefined)
if(this.auth){
+21 -7
View File
@@ -129,6 +129,18 @@ describe('Frontcraft', () => {
return client.UserManager.createUser(user)
}
const login = async (name: string) : Promise<Auth> => {
const auth = await client.UserManager.login(name, 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb')
if(users[name]) users[name] = {
...users[name],
auth: auth
}
return auth
}
const createAccountAndUser = async (acc: protoAccount) => {
const account = await createAccount({
pwhash: 'ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb', //sha256("a")
@@ -199,6 +211,14 @@ describe('Frontcraft', () => {
server.stop()
})
it('can set permissions', (done) => {
Promise.all(
defaultPermissions.map(perm => adminClient.modifyPermissions.setPermission(perm)),
).then(_ => {
done()
})
})
it('create raids', (done) => {
let insertRaid = <Raid>{
description: "Test raid 1",
@@ -587,13 +607,7 @@ describe('Frontcraft', () => {
})
})
it('can set permissions', (done) => {
Promise.all(
defaultPermissions.map(perm => adminClient.modifyPermissions.setPermission(perm)),
).then(_ => {
done()
})
})
it('start raid', (done) => {
client.RaidManager.getRaids().then((r) => {