diff --git a/package-lock.json b/package-lock.json index ca3b76e..2669275 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4961,9 +4961,9 @@ } }, "rpclibrary": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.4.0.tgz", - "integrity": "sha512-JUU7+HymV2ZTI+NrIVOiIr5LGFoRsPq4k/ffdUonqIpd9fjOHBQ2/PFLVXx9z94+dKxdqN8/D9ZXPwU03ovZrg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.4.1.tgz", + "integrity": "sha512-Tv9zOBVT8JFMZfTJgmnX9vvUvtALCDtj/cnlYw2SxsFnj1MuH9VgPniSfThUgdwZZknjFuYVfhLaYb9Yl+eRxQ==", "requires": { "bsock": "^0.1.9", "http": "0.0.0", diff --git a/package.json b/package.json index 9c57807..de01e6c 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "node-fetch": "^2.6.0", "path": "^0.12.7", "rimraf": "^3.0.0", - "rpclibrary": "^1.4.0", + "rpclibrary": "^1.4.1", "simple-git": "^1.124.0", "spawn-sync": "^2.0.0", "sqlite3": "^4.1.0", diff --git a/src/backend/Admin/Admin.ts b/src/backend/Admin/Admin.ts index 61b4548..d9b5e84 100644 --- a/src/backend/Admin/Admin.ts +++ b/src/backend/Admin/Admin.ts @@ -146,12 +146,19 @@ implements TableDefinitionExporter { this.knex = Knex(conf) - await Promise.all(this.getTableDefinitions().map(async (def)=>{ - const hasTable = await this.knex.schema.hasTable(def.name) - if(!hasTable){ - await this.knex.schema.createTable(def.name, def.tableBuilder) - } - })) + await Promise.all( + this.getTableDefinitions() + //make unique by name + .filter((other, index, self) => index === self.findIndex( + (self) => self.name === other.name) + ) + //create table if not exists + .map(async (def)=> { + const hasTable = await this.knex.schema.hasTable(def.name) + if(!hasTable) + return await this.knex.schema.createTable(def.name, def.tableBuilder) + }) + ) return this.knex } diff --git a/src/backend/Components/Item/ItemManager.ts b/src/backend/Components/Item/ItemManager.ts index 933489b..22d7026 100644 --- a/src/backend/Components/Item/ItemManager.ts +++ b/src/backend/Components/Item/ItemManager.ts @@ -94,13 +94,13 @@ implements FrontworkComponent, TableDefinitionExporter{ const allItems = [...T1] const countCache = await this.countItems() if(countCache != allItems.length){ - const items:Item[] = await Promise.all(allItems.map(async (i) => this.getItem(i))) + const items:Item[] = await Promise.all(allItems.map((i) => this.getItem(i))) try{ await this.admin .knex('items') .insert(items) }catch(e){ - console.error(e) + console.info("Skipping item insertion") } } } diff --git a/src/backend/Components/Login/LoginManager.ts b/src/backend/Components/Login/LoginManager.ts index d21d0f1..006d7d6 100644 --- a/src/backend/Components/Login/LoginManager.ts +++ b/src/backend/Components/Login/LoginManager.ts @@ -1,5 +1,5 @@ import { RPCServer } from "rpclibrary"; -import { TableDefiniton, AnyRPCExporter, User, RPCPermission, _Rank, Token, Auth } from "../../Types/Types"; +import { TableDefiniton, AnyRPCExporter, User, RPCPermission, _Rank, Token, Auth, FrontcraftFeatureIfc, Rank } from "../../Types/Types"; import { FrontworkAdmin } from "../../Admin/Admin"; import { PrivilegedRPCExporter } from "../../Types/PrivilegedRPCExporter"; import { FrontworkComponent } from "../../Types/FrontworkComponent"; @@ -65,7 +65,7 @@ implements FrontworkComponent{ },{ name: 'rpcpermissions', tableBuilder: (table) => { - table.string("rpcName").primary().notNullable() + table.string("name").primary().notNullable() table.boolean("ADMIN").defaultTo(true).notNullable() _Rank.forEach(r => table.boolean(r).defaultTo(false).notNullable()) } @@ -83,9 +83,9 @@ implements FrontworkComponent{ async initialize(){ await Promise.all( - [this, ...this.exporters].flatMap(exp => exp.exportRPCFeatures().map(async (rpc) => { + [this, ...this.exporters].flatMap(exp => exp.exportRPCFeatures().map(async (feature) => { try{ - await this.admin.knex.insert({ rpcname: rpc.name }).into('rpcpermissions') + await this.admin.knex.insert({ name: feature.name }).into('rpcpermissions') }catch(e){} }))) @@ -102,8 +102,21 @@ implements FrontworkComponent{ return await this.admin.knex.select('*').from('rpcpermissions') } + getPermission = async (feature: keyof FrontcraftFeatureIfc, rank:Rank) : Promise => { + const perm : RPCPermission[] = await this.admin.knex + .select(rank) + .from('rpcpermissions') + .where('name', '=', feature) + + if(perm.length === 0) return false + return perm[0][rank] + } + getRPCForUser = async (user:User): Promise => { - return [...this.exportRPCFeatures(), ...this.exporters.flatMap((exp) => exp.exportRPCFeatures())] + return [ + ...this.exportRPCFeatures(), + ...this.exporters.flatMap((exp) => exp.exportRPCFeatures()) + ].filter(async (feature) => await this.getPermission( feature.name, user.rank)) } createUser = async(user:User): Promise => { diff --git a/src/backend/Types/Types.ts b/src/backend/Types/Types.ts index 6e1a521..f4b44e3 100644 --- a/src/backend/Types/Types.ts +++ b/src/backend/Types/Types.ts @@ -88,4 +88,8 @@ export type RaidManagerFeatureIfc = { getSingups: (raid:Raid) => Promise sign: (user:User, raid:Raid, attending:boolean) => Promise } +} + +export type SomeOf = { + [K in keyof T]? : T[K] } \ No newline at end of file diff --git a/src/frontend/package-lock.json b/src/frontend/package-lock.json index 9651268..8daeb97 100644 --- a/src/frontend/package-lock.json +++ b/src/frontend/package-lock.json @@ -14269,9 +14269,9 @@ "integrity": "sha512-ZYzRkETgBrdEGzL5JSKimvjI2CX7ioyZCkX2BpcfyjqI+079W0wHAyj5W4rIZMcDSOHgLZtgz1IdDi/vU77KEQ==" }, "rpclibrary": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.4.0.tgz", - "integrity": "sha512-JUU7+HymV2ZTI+NrIVOiIr5LGFoRsPq4k/ffdUonqIpd9fjOHBQ2/PFLVXx9z94+dKxdqN8/D9ZXPwU03ovZrg==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.4.2.tgz", + "integrity": "sha512-IFigD+65a9MM+1AgEH5nurUzCyMg9hawqtnOA67/PtTGP5GsnWxaFESKl03k8L/PQ8ptZkWcub/63bfxkrwyMw==", "requires": { "bsock": "^0.1.9", "http": "0.0.0", diff --git a/src/frontend/package.json b/src/frontend/package.json index 643f76f..db5badc 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -69,7 +69,7 @@ "normalize.css": "6.0.0", "pace-js": "1.0.2", "roboto-fontface": "0.8.0", - "rpclibrary": "^1.4.0", + "rpclibrary": "^1.4.2", "rxjs": "6.5.2", "rxjs-compat": "6.3.0", "socicon": "3.0.5", diff --git a/src/frontend/src/app/app.component.ts b/src/frontend/src/app/app.component.ts index d9e24c9..109e1b6 100644 --- a/src/frontend/src/app/app.component.ts +++ b/src/frontend/src/app/app.component.ts @@ -19,6 +19,9 @@ export class AppComponent implements OnInit { ngOnInit(): void { this.analytics.trackPageViews(); + this.loginSvc.getFeature('createUser').then( (f) => { + + }) window['s'] = this.loginSvc } } diff --git a/src/frontend/src/app/frontcraft/login-api.ts b/src/frontend/src/app/frontcraft/login-api.ts index df78391..48a65a1 100644 --- a/src/frontend/src/app/frontcraft/login-api.ts +++ b/src/frontend/src/app/frontcraft/login-api.ts @@ -1,14 +1,14 @@ import { Injectable } from "@angular/core"; import {RPCSocket} from 'rpclibrary/js/src/Frontend' -import { Token, Auth, User, _Rank, _Class, FrontcraftFeatureIfc, LoginManagerIfc, } from '../../../../backend/Types/Types' +import { Token, Auth, User, _Class, FrontcraftFeatureIfc, LoginManagerIfc, SomeOf, } from '../../../../backend/Types/Types' import { CookieService } from 'ngx-cookie-service'; @Injectable() export class LoginApiService{ private socket:RPCSocket & LoginManagerIfc; private auth:Auth - private privSocket: RPCSocket & FrontcraftFeatureIfc + private privSocket: RPCSocket & SomeOf constructor( private cookieSvc : CookieService @@ -16,10 +16,21 @@ export class LoginApiService{ getUnprivilegedSocket = () : RPCSocket & LoginManagerIfc => this.socket - private getPrivilegedSocket = async (auth:Auth) : Promise => { + private getPrivilegedSocket = async (auth:Auth) : Promise> => { if(this.privSocket) return this.privSocket + if(auth.user.rank === 'Guest'){ + return await RPCSocket.makeSocket>( + 20001, + window.location.hostname + ) + } try{ - const sock: RPCSocket & FrontcraftFeatureIfc = await new RPCSocket(auth.port, window.location.hostname).connect(auth.token.value) + const sock = await RPCSocket.makeSocket>( + auth.port, + window.location.hostname, + auth.token.value + ) + //login success this.auth = auth this.privSocket = sock @@ -29,7 +40,12 @@ export class LoginApiService{ //login failed throw new Error('login failed') } - } + } + + getFeature = async (feature : K) : Promise => { + const sock = await this.getPrivilegedSocket(this.auth) + if(sock[feature]) return sock[feature] + } getCurrentUser = () : User => this.auth ? this.auth.user @@ -40,12 +56,12 @@ export class LoginApiService{ rank: 'Guest' } - authenticate = async (token : Token | string) : Promise => { + authenticate = async (token : Token | string) : Promise> => { const auth = await this.socket.Authenticator.authenticate(token) return await this.getPrivilegedSocket(auth) } - login = async (username, password) => { + login = async (username: string, password: string) => { const buf = str2arraybuf(password) const pwHash = await crypto.subtle.digest('SHA-256', buf); const token = await this.socket.Authenticator.login(username, buf2hex(pwHash)) @@ -69,12 +85,16 @@ export class LoginApiService{ } initialize = async () : Promise => { - const sock : RPCSocket & LoginManagerIfc = await new RPCSocket(20000, window.location.hostname).connect() + const sock = await RPCSocket.makeSocket(20000, window.location.hostname) this.socket = sock const cookie = this.getCookie() if(cookie) { - return await this.authenticate(cookie) + try{ + return await this.authenticate(cookie) + }catch(e){ + this.logout() + } } return sock @@ -89,7 +109,7 @@ function buf2hex(buffer) { // buffer is an ArrayBuffer return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join(''); } - -export function initializeLoginSvc(svc: LoginApiService): () => Promise { +//angular depenency manager requires this +export function initializeLoginSvc(svc: LoginApiService): () => Promise { return svc.initialize } \ No newline at end of file