Browse Source

Added dependency injection

master
peter 5 years ago
parent
commit
e4a6972884

+ 1262
- 43
package-lock.json
File diff suppressed because it is too large
View File


+ 8
- 2
package.json View File

4
   "version": "1.0.0",
4
   "version": "1.0.0",
5
   "scripts": {
5
   "scripts": {
6
     "tsc": "tsc",
6
     "tsc": "tsc",
7
-    "start": "npm run build; node lib/Launcher.js",
7
+    "start": "npm run build; node lib/src/Launcher.js",
8
     "build": "npm run clean; npm run build-backend; npm run build-frontend",
8
     "build": "npm run clean; npm run build-backend; npm run build-frontend",
9
+    "test": "npm run clean && npm run build-backend && mocha lib/test/backendTest.js",
9
     "build-backend": "tsc;",
10
     "build-backend": "tsc;",
10
     "build-frontend": "mkdir dist; mkdir dist/static; npm run build-dashboard;",
11
     "build-frontend": "mkdir dist; mkdir dist/static; npm run build-dashboard;",
11
     "build-dashboard": "cd src/frontend; npm i && npm run build; cp -r dist/* ../../dist/static",
12
     "build-dashboard": "cd src/frontend; npm i && npm run build; cp -r dist/* ../../dist/static",
20
   "author": "frontblock.me",
21
   "author": "frontblock.me",
21
   "license": "ISC",
22
   "license": "ISC",
22
   "dependencies": {
23
   "dependencies": {
24
+    "@types/mocha": "^5.2.7",
23
     "bsert": "0.0.10",
25
     "bsert": "0.0.10",
24
     "bsock": "^0.1.9",
26
     "bsock": "^0.1.9",
25
     "child-process-promise": "^2.2.1",
27
     "child-process-promise": "^2.2.1",
34
     "loadson": "^1.0.0",
36
     "loadson": "^1.0.0",
35
     "log4js": "^4.5.1",
37
     "log4js": "^4.5.1",
36
     "lowdb": "^1.0.0",
38
     "lowdb": "^1.0.0",
39
+    "mocha": "^7.0.0",
37
     "node-fetch": "^2.6.0",
40
     "node-fetch": "^2.6.0",
38
     "path": "^0.12.7",
41
     "path": "^0.12.7",
42
+    "reflect-metadata": "^0.1.13",
39
     "rimraf": "^3.0.0",
43
     "rimraf": "^3.0.0",
40
-    "rpclibrary": "^1.5.2",
44
+    "rpclibrary": "^1.6.2",
41
     "simple-git": "^1.124.0",
45
     "simple-git": "^1.124.0",
42
     "spawn-sync": "^2.0.0",
46
     "spawn-sync": "^2.0.0",
43
     "sqlite3": "^4.1.0",
47
     "sqlite3": "^4.1.0",
44
     "trash": "^6.0.0",
48
     "trash": "^6.0.0",
49
+    "tsyringe": "^4.0.1",
45
     "upgiter": "^1.0.4",
50
     "upgiter": "^1.0.4",
46
     "uuid": "^3.3.3",
51
     "uuid": "^3.3.3",
47
     "xml2js": "^0.4.22"
52
     "xml2js": "^0.4.22"
50
     "@types/express": "^4.17.0",
55
     "@types/express": "^4.17.0",
51
     "@types/node": "^11.13.19",
56
     "@types/node": "^11.13.19",
52
     "@types/semver": "^6.0.1",
57
     "@types/semver": "^6.0.1",
58
+    "madge": "^3.6.0",
53
     "terser-webpack-plugin": "^1.4.1",
59
     "terser-webpack-plugin": "^1.4.1",
54
     "ts-loader": "^5.3.3",
60
     "ts-loader": "^5.3.3",
55
     "typescript": "^3.5.3",
61
     "typescript": "^3.5.3",

+ 30
- 14
src/backend/Admin/Admin.ts View File

3
 import { getLogger } from 'frontblock-generic/Types';
3
 import { getLogger } from 'frontblock-generic/Types';
4
 import { promises as fs, mkdirSync } from "fs"
4
 import { promises as fs, mkdirSync } from "fs"
5
 import { RPCServer } from 'rpclibrary'
5
 import { RPCServer } from 'rpclibrary'
6
-import { AdminConf, TableDefiniton } from '../Types/Types';
7
-import { RPCConfigLoader } from '../Components/RPCConfigLoader';
8
 import * as Path from 'path'
6
 import * as Path from 'path'
9
 import * as Knex from  'knex';
7
 import * as Knex from  'knex';
10
 import * as http from 'http';
8
 import * as http from 'http';
11
 import * as express from 'express';
9
 import * as express from 'express';
10
+import { GuildManager } from '../Components/Guild/GuildManager';
11
+import { ItemManager } from '../Components/Item/ItemManager';
12
+import { RaidManager } from '../Components/Raid/RaidManager';
13
+import { CharacterManager } from '../Components/User/CharacterManager';
14
+import { LoginManager } from '../Components/User/LoginManager';
15
+import { RootComponent } from '../Injector/ServiceDecorator';
12
 import { TableDefinitionExporter } from '../Types/Interfaces';
16
 import { TableDefinitionExporter } from '../Types/Interfaces';
17
+import { AdminConf, TableDefiniton } from '../Types/Types';
18
+import { RPCConfigLoader } from '../Components/RPCConfigLoader';
13
 import { FrontworkComponent } from '../Types/FrontworkComponent';
19
 import { FrontworkComponent } from '../Types/FrontworkComponent';
20
+import { IAdmin } from './Interface';
21
+
14
 
22
 
15
 const logger = getLogger("admin", 'debug') 
23
 const logger = getLogger("admin", 'debug') 
16
 
24
 
25
+@RootComponent({
26
+    rootInterface: IAdmin,
27
+    imports: [
28
+        GuildManager,
29
+        ItemManager,
30
+        RaidManager,
31
+        CharacterManager,
32
+        LoginManager
33
+    ]
34
+})
17
 export class FrontworkAdmin 
35
 export class FrontworkAdmin 
18
-implements TableDefinitionExporter {
36
+implements TableDefinitionExporter, IAdmin {
19
     knex:Knex
37
     knex:Knex
20
     config: RPCConfigLoader<AdminConf>
38
     config: RPCConfigLoader<AdminConf>
21
     rpcServer: RPCServer
39
     rpcServer: RPCServer
23
     private express
41
     private express
24
     private httpServer
42
     private httpServer
25
 
43
 
26
-    constructor(private components: FrontworkComponent[]){
44
+    constructor(private frontworkComponents: FrontworkComponent[] = []){
27
         this.config = new RPCConfigLoader<AdminConf>({
45
         this.config = new RPCConfigLoader<AdminConf>({
28
             name: "FrontworkAdminConf", 
46
             name: "FrontworkAdminConf", 
29
             getDefaultConfig: () => {
47
             getDefaultConfig: () => {
40
                 }   
58
                 }   
41
             }
59
             }
42
         }, './config', this.configChangeHandler) 
60
         }, './config', this.configChangeHandler) 
43
-
44
-        components.forEach(c => {
45
-            c.admin = this
46
-            if(c.onSetAdmin) c.onSetAdmin(this)
47
-        })
48
     }
61
     }
49
 
62
 
50
     async start(){
63
     async start(){
51
         await this.makeKnex()
64
         await this.makeKnex()
52
         this.startWebsocket()
65
         this.startWebsocket()
53
-        await Promise.all( this.components.map(c => c.initialize?c.initialize():undefined ))
66
+        await Promise.all( this.frontworkComponents.map(c => c.initialize?c.initialize():undefined ))
54
         this.startWebserver()
67
         this.startWebserver()
55
-        
68
+    }
69
+
70
+    stop(){
71
+        process.exit(0);
56
     }
72
     }
57
 
73
 
58
     protected configChangeHandler = (conf:AdminConf, key?:string) => {
74
     protected configChangeHandler = (conf:AdminConf, key?:string) => {
71
 
87
 
72
     getTableDefinitions(): TableDefiniton[]{
88
     getTableDefinitions(): TableDefiniton[]{
73
         return [
89
         return [
74
-            ...this.components
90
+            ...this.frontworkComponents
75
         ].flatMap(exporter => exporter.getTableDefinitions())
91
         ].flatMap(exporter => exporter.getTableDefinitions())
76
     }
92
     }
77
 
93
 
78
     private startWebsocket(){
94
     private startWebsocket(){
79
         this.rpcServer = new RPCServer(20000, [
95
         this.rpcServer = new RPCServer(20000, [
80
-            ...this.components,
96
+            ...this.frontworkComponents,
81
         ])
97
         ])
82
     }
98
     }
83
 
99
 
169
     logger.info("Shutting down from SIGINT (Ctrl-C)" );
185
     logger.info("Shutting down from SIGINT (Ctrl-C)" );
170
     // some other closing procedures go here
186
     // some other closing procedures go here
171
     process.exit(0);
187
     process.exit(0);
172
-})
188
+})

+ 13
- 0
src/backend/Admin/Interface.ts View File

1
+import { RPCConfigLoader } from "../Components/RPCConfigLoader"
2
+import { AdminConf } from "../Types/Types"
3
+import { RPCServer } from "rpclibrary"
4
+import Knex = require("knex")
5
+
6
+export class IAdmin{
7
+    knex: Knex
8
+    config: RPCConfigLoader<AdminConf>
9
+    rpcServer: RPCServer
10
+    
11
+    start: ()=>Promise<void>
12
+    stop: ()=>void
13
+}

+ 9
- 4
src/backend/Components/Guild/GuildManager.ts View File

1
+import { ConfigLoader } from "loadson";
2
+import { Inject, Module } from "../../Injector/ServiceDecorator";
3
+import { GuildManagerFeatureIfc, GuildManagerIfc } from "./RPCInterface";
1
 import { FrontworkAdmin } from "../../Admin/Admin";
4
 import { FrontworkAdmin } from "../../Admin/Admin";
2
 import { FrontworkComponent } from "../../Types/FrontworkComponent";
5
 import { FrontworkComponent } from "../../Types/FrontworkComponent";
3
 import { _Rank, Rank } from "../../Types/Types";
6
 import { _Rank, Rank } from "../../Types/Types";
4
-import { ConfigLoader } from "loadson";
5
-import { GuildManagerIfc, GuildManagerFeatureIfc } from "./RPCInterface";
7
+import { IAdmin } from "../../Admin/Interface";
6
 
8
 
7
 export type Guild = {
9
 export type Guild = {
8
     name: string
10
     name: string
10
     description: string
12
     description: string
11
 }
13
 }
12
 
14
 
15
+@Module()
13
 export class GuildManager
16
 export class GuildManager
14
 implements FrontworkComponent<GuildManagerIfc, GuildManagerFeatureIfc>{
17
 implements FrontworkComponent<GuildManagerIfc, GuildManagerFeatureIfc>{
15
 
18
 
16
     name = "GuildManager" as "GuildManager";    
19
     name = "GuildManager" as "GuildManager";    
17
-    admin: FrontworkAdmin
20
+    
21
+    @Inject(IAdmin)
22
+    private admin
18
 
23
 
19
     guild: ConfigLoader<Guild>
24
     guild: ConfigLoader<Guild>
20
 
25
 
56
     getTableDefinitions = () => []
61
     getTableDefinitions = () => []
57
 
62
 
58
     headCount = async () => await Promise.all(
63
     headCount = async () => await Promise.all(
59
-        ['ADMIN', ..._Rank].map(async r => {
64
+        _Rank.map(async r => {
60
             const res = await this.admin.knex
65
             const res = await this.admin.knex
61
             .select('*')
66
             .select('*')
62
             .from('users')
67
             .from('users')

+ 18
- 10
src/backend/Components/Item/ItemManager.ts View File

1
-import { TableDefinitionExporter } from "../../Types/Interfaces";
2
-import { TableDefiniton, _Rank } from "../../Types/Types";
3
-import { FrontworkAdmin } from "../../Admin/Admin";
4
 import { T1 } from "../../Types/Items";
1
 import { T1 } from "../../Types/Items";
2
+import { RPC } from "rpclibrary";
3
+import { Inject, Module } from "../../Injector/ServiceDecorator";
4
+import { ItemManagerFeatureIfc, ItemManagerIfc } from "./RPCInterface";
5
 import { FrontworkComponent } from "../../Types/FrontworkComponent";
5
 import { FrontworkComponent } from "../../Types/FrontworkComponent";
6
-import { RPC, RPCInterface } from "rpclibrary";
7
-import { ItemManagerIfc, ItemManagerFeatureIfc } from "./RPCInterface";
6
+import { TableDefinitionExporter } from "../../Types/Interfaces";
7
+import { FrontworkAdmin } from "../../Admin/Admin";
8
+import { TableDefiniton } from "../../Types/Types";
9
+import { IAdmin } from "../../Admin/Interface";
10
+
8
 const fetch = require('node-fetch')
11
 const fetch = require('node-fetch')
9
 const xml2js = require('xml2js');
12
 const xml2js = require('xml2js');
10
 const parser = new xml2js.Parser(/* options */);
13
 const parser = new xml2js.Parser(/* options */);
11
 
14
 
12
-
13
-
14
 export type Item = {
15
 export type Item = {
15
     id?:number
16
     id?:number
16
     name:string
17
     name:string
20
     hidden:boolean
21
     hidden:boolean
21
 }
22
 }
22
 
23
 
24
+@Module()
23
 export class ItemManager
25
 export class ItemManager
24
 implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefinitionExporter{
26
 implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefinitionExporter{
25
-    
26
-    admin:FrontworkAdmin    
27
     name = "ItemManager" as "ItemManager";    
27
     name = "ItemManager" as "ItemManager";    
28
     
28
     
29
+    @Inject(IAdmin)
30
+    private admin: FrontworkAdmin
31
+
29
     exportRPCs(): RPC<any, any>[]{
32
     exportRPCs(): RPC<any, any>[]{
30
         return [{
33
         return [{
31
             name: 'getItems',
34
             name: 'getItems',
90
         return <number>count[0]['count(*)']
93
         return <number>count[0]['count(*)']
91
     }
94
     }
92
 
95
 
93
-    initialize = async() => {
96
+    private initialized = false
97
+    initialize = async () => {
98
+        if(!this.initialized)
99
+            this.initialized = true        
100
+        
94
         const allItems = [...T1]
101
         const allItems = [...T1]
95
         const countCache = await this.countItems()
102
         const countCache = await this.countItems()
96
         if(countCache != allItems.length){
103
         if(countCache != allItems.length){
100
                 .knex('items')
107
                 .knex('items')
101
                 .insert(items)
108
                 .insert(items)
102
             }catch(e){
109
             }catch(e){
110
+                console.log(e)
103
                 console.info("Skipping item insertion")
111
                 console.info("Skipping item insertion")
104
             }
112
             }
105
         }
113
         }

+ 6
- 3
src/backend/Components/Raid/RPCInterface.ts View File

1
-import { Raid, Signup, User } from "../../Types/Types";
2
-import { RPCInterface } from "rpclibrary";
1
+import { Raid, Signup, User } from "../../Types/Types"
3
 
2
 
4
-export type RaidManagerIfc = RPCInterface
3
+export type RaidManagerIfc = {
4
+    RaidManager:{
5
+        getRaids: () => Promise<Raid[]>
6
+    }
7
+}
5
 
8
 
6
 export type RaidManagerFeatureIfc = {
9
 export type RaidManagerFeatureIfc = {
7
     manageRaid: {
10
     manageRaid: {

+ 17
- 11
src/backend/Components/Raid/RaidManager.ts View File

1
-import { TableDefiniton, User, _Rank, Raid, Signup } from "../../Types/Types";
2
-import { FrontworkAdmin } from "../../Admin/Admin";
1
+import { Inject, Module } from "../../Injector/ServiceDecorator";
2
+import { RaidManagerIfc, RaidManagerFeatureIfc } from "./RPCInterface";
3
 import { FrontworkComponent } from "../../Types/FrontworkComponent";
3
 import { FrontworkComponent } from "../../Types/FrontworkComponent";
4
-import { RaidManagerFeatureIfc, RaidManagerIfc } from "./RPCInterface";
4
+import { FrontworkAdmin } from "../../Admin/Admin";
5
+import { TableDefiniton, Signup, Raid, User } from "../../Types/Types";
6
+import { IAdmin } from "../../Admin/Interface";
5
 
7
 
8
+@Module()
6
 export class RaidManager
9
 export class RaidManager
7
 implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>{
10
 implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>{
8
     name = "RaidManager" as "RaidManager";    
11
     name = "RaidManager" as "RaidManager";    
9
-    admin: FrontworkAdmin
10
 
12
 
11
-    exportRPCs = () => []
13
+    @Inject(IAdmin)
14
+    private admin: FrontworkAdmin
15
+
16
+    exportRPCs = () => [{
17
+        name: 'getRaids' as 'getRaids',
18
+        call: this.getRaids
19
+    },]
12
 
20
 
13
     exportRPCFeatures() {
21
     exportRPCFeatures() {
14
         return [{
22
         return [{
26
         },{
34
         },{
27
             name: 'signup' as 'signup',
35
             name: 'signup' as 'signup',
28
             exportRPCs: () => [{
36
             exportRPCs: () => [{
29
-                name: 'getRaids' as 'getRaids',
30
-                call: this.getRaids
31
-            },{
32
                 name: 'getSingups' as 'getSingups',
37
                 name: 'getSingups' as 'getSingups',
33
                 call: this.getSignups
38
                 call: this.getSignups
34
             },{
39
             },{
52
             },{
57
             },{
53
                 name: 'signups',
58
                 name: 'signups',
54
                 tableBuilder: (table) => {
59
                 tableBuilder: (table) => {
55
-                    table.integer('raid_id').primary()
60
+                    table.primary(['raid_id', 'user_id'])
61
+                    table.integer('raid_id')
56
                     table.foreign('raid_id').references('id').inTable('raids')
62
                     table.foreign('raid_id').references('id').inTable('raids')
57
-                    table.integer('user_id').primary()
63
+                    table.integer('user_id')
58
                     table.foreign('user_id').references('id').inTable('users')
64
                     table.foreign('user_id').references('id').inTable('users')
59
                 }
65
                 }
60
             }            
66
             }            
77
     })
83
     })
78
     .delete()
84
     .delete()
79
 
85
 
80
-    getRaids = async () => await this.admin.knex
86
+    getRaids = async () : Promise<Raid[]> => await this.admin.knex
81
     .select('*')
87
     .select('*')
82
     .from('raids')
88
     .from('raids')
83
     
89
     

+ 96
- 0
src/backend/Components/User/CharacterManager.ts View File

1
+import { RPCInterface } from "rpclibrary";
2
+import { Inject, Module } from "../../Injector/ServiceDecorator";
3
+import { TableDefiniton, Character } from "../../Types/Types";
4
+import { CharacterManagerIfc } from "./RPCInterface";
5
+import { FrontworkComponent } from "../../Types/FrontworkComponent";
6
+import { FrontworkAdmin } from "../../Admin/Admin";
7
+import { LoginManager } from "./LoginManager";
8
+import { getSpecTableData, SpecT } from "../../Types/PlayerSpecs";
9
+import { IAdmin } from "../../Admin/Interface";
10
+
11
+@Module()
12
+export class CharacterManager
13
+implements FrontworkComponent<CharacterManagerIfc, RPCInterface>{
14
+    name = "CharacterManager" as "CharacterManager";   
15
+    
16
+    @Inject(IAdmin)
17
+    private admin: IAdmin   
18
+
19
+    private loginManager : LoginManager
20
+
21
+    exportRPCs = () => [
22
+        {
23
+           name: 'getSpecId' as 'getSpecId',
24
+           call: this.getSpecId
25
+        }
26
+    ]
27
+
28
+    exportRPCFeatures = () => [
29
+        {
30
+            name: "createCharacter",
31
+            exportRPCs: () => [
32
+                {
33
+                    name: 'createCharacter',
34
+                    call: this.createCharacter
35
+                }
36
+            ]
37
+        }
38
+    ]
39
+    
40
+    getTableDefinitions = (): TableDefiniton[] => [
41
+        {
42
+            name: 'characters',
43
+            tableBuilder: (table) => {
44
+                table.increments("id").primary()
45
+                table.string("name").notNullable().unique()
46
+                table.integer("specid").notNullable()
47
+                table.foreign("specid").references("specs.id")
48
+                table.integer("userid").notNullable()
49
+                table.foreign("userid").references("users.id")
50
+            }
51
+        },{
52
+            name: 'specs',
53
+            tableBuilder: (table) => {
54
+                table.increments("id")
55
+                table.string('class')
56
+                table.string('name')
57
+                table.unique(['class', 'name'])
58
+            }
59
+        }
60
+    ]
61
+
62
+    private initialized = false
63
+    initialize = async () => {
64
+
65
+        if(!this.initialized)
66
+            this.initialized = true
67
+        //initialize spec table
68
+        await this.admin.knex('specs').insert(getSpecTableData()).catch(e => { console.log("skipping spec insertion") })
69
+    }
70
+
71
+    createCharacter = async (userToken: string, character : Character) : Promise<Character> => {
72
+        try{
73
+
74
+            await this.admin.knex('characters').insert(character)
75
+            const char : Character = await this.admin.knex.select('*').from('characters').where(character).first()
76
+            return char
77
+        }catch(e){
78
+            console.log(e);
79
+            
80
+        }
81
+        throw new Error('Unable to create character')
82
+    }
83
+
84
+    getCharacters = async() : Promise<Character[]> => {
85
+        return this.admin.knex.select('*').from('characters')
86
+    }
87
+
88
+    getSpecId = async <c extends keyof SpecT>(clazz: c, name: SpecT[c]) => await this.admin.knex
89
+    .from('specs')
90
+    .select('id')
91
+    .where({
92
+        class: clazz,
93
+        name: name
94
+    }).first().then(spec => spec.id)
95
+
96
+}

+ 78
- 51
src/backend/Components/User/LoginManager.ts View File

1
 import { RPCServer, Socket } from "rpclibrary";
1
 import { RPCServer, Socket } from "rpclibrary";
2
-import { TableDefiniton, AnyRPCExporter, User, RPCPermission, Token, Auth, Rank, FrontcraftFeatureIfc, _Rank } from "../../Types/Types";
2
+import { Inject, Module } from "../../Injector/ServiceDecorator";
3
 import { FrontworkAdmin } from "../../Admin/Admin";
3
 import { FrontworkAdmin } from "../../Admin/Admin";
4
-import { PrivilegedRPCExporter } from "../../Types/PrivilegedRPCExporter";
5
-import { FrontworkComponent } from "../../Types/FrontworkComponent";
6
-import { getSpecTableData } from "../../Types/PlayerSpecs"
4
+import { GuildManager } from "../Guild/GuildManager";
5
+import { ItemManager } from "../Item/ItemManager";
6
+import { RaidManager } from "../Raid/RaidManager";
7
+import { CharacterManager } from "./CharacterManager";
7
 import { LoginManagerIfc, LoginManagerFeatureIfc } from "./RPCInterface";
8
 import { LoginManagerIfc, LoginManagerFeatureIfc } from "./RPCInterface";
9
+import { FrontworkComponent } from "../../Types/FrontworkComponent";
10
+import { Rank, User, Auth, _Rank, TableDefiniton, RPCPermission, FrontcraftFeatureIfc, AnyRPCExporter, Token } from "../../Types/Types";
11
+import { IAdmin } from "../../Admin/Interface";
12
+
8
 const uuid = require('uuid/v4')
13
 const uuid = require('uuid/v4')
9
 
14
 
10
 const ONE_WEEK = 604800000 
15
 const ONE_WEEK = 604800000 
15
     allowed: string[]
20
     allowed: string[]
16
 }
21
 }
17
 
22
 
23
+
24
+@Module()
18
 export class LoginManager
25
 export class LoginManager
19
 implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>{
26
 implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>{
20
     name = "Authenticator" as "Authenticator";   
27
     name = "Authenticator" as "Authenticator";   
21
-    admin:FrontworkAdmin
28
+
29
+    @Inject(IAdmin)
30
+    private admin: FrontworkAdmin
31
+
32
+    @Inject(GuildManager)
33
+    private guild : GuildManager
34
+    
35
+    @Inject(ItemManager)
36
+    private item : ItemManager
37
+    
38
+    @Inject(RaidManager)
39
+    private raid : RaidManager
22
     
40
     
41
+    @Inject(CharacterManager)
42
+    private character : CharacterManager
43
+    
44
+    exporters :any[] = []
23
     rankServers : {[rank in Rank] : Serverstate}
45
     rankServers : {[rank in Rank] : Serverstate}
24
     userLogins : {[username in string] : {
46
     userLogins : {[username in string] : {
47
+        user: User
25
         connections: {[port in number]: Socket}
48
         connections: {[port in number]: Socket}
26
         auth: Auth
49
         auth: Auth
27
     }} = {}
50
     }} = {}
28
 
51
 
29
-    constructor(
30
-        private exporters: PrivilegedRPCExporter[]
31
-    ){}
32
-
33
     exportRPCs = () => [
52
     exportRPCs = () => [
34
         {
53
         {
35
             name: 'login' as 'login',
54
             name: 'login' as 'login',
43
         },{
62
         },{
44
             name: 'checkToken' as 'checkToken',
63
             name: 'checkToken' as 'checkToken',
45
             call: async (tokenValue : string, rank: Rank) => this.checkToken(tokenValue, rank)
64
             call: async (tokenValue : string, rank: Rank) => this.checkToken(tokenValue, rank)
65
+        },{
66
+            name: 'createUser' as 'createUser',
67
+            call: this.createUser
46
         }
68
         }
47
     ]
69
     ]
48
 
70
 
49
-    onSetAdmin(admin:FrontworkAdmin){
50
-        this.exporters.forEach(e => e['admin'] = admin)
51
-    }
52
-
53
     exportRPCFeatures = () => [
71
     exportRPCFeatures = () => [
54
         {
72
         {
55
-            name: 'createUser' as 'createUser',
56
-            exportRPCs: () => [{
57
-                name: 'createUser' as 'createUser',
58
-                call: this.createUser
59
-            }]
60
-        },{
61
             name: 'modifyPermissions' as 'modifyPermissions',
73
             name: 'modifyPermissions' as 'modifyPermissions',
62
             exportRPCs: () => [{
74
             exportRPCs: () => [{
63
                 name: 'getPermissions' as 'getPermissions',
75
                 name: 'getPermissions' as 'getPermissions',
79
                 table.string("pwhash").notNullable()
91
                 table.string("pwhash").notNullable()
80
                 table.string("rank").notNullable()
92
                 table.string("rank").notNullable()
81
                 table.string("email").nullable().unique()
93
                 table.string("email").nullable().unique()
82
-            }
83
-        },{
84
-            name: 'characters',
85
-            tableBuilder: (table) => {
86
-                table.increments("id").primary()
87
-                table.string("name").notNullable().unique()
88
-                table.integer("specid").notNullable()
89
-                table.foreign("specid").references("specs.id")
90
-                table.integer("userid").notNullable()
91
-                table.foreign("userid").references("users.id")
94
+                table.boolean("locked").defaultTo(true)
92
             }
95
             }
93
         },{
96
         },{
94
             name: 'rpcpermissions',
97
             name: 'rpcpermissions',
95
             tableBuilder: (table) => {
98
             tableBuilder: (table) => {
96
                 table.string("name").primary().notNullable()
99
                 table.string("name").primary().notNullable()
97
-                table.boolean("ADMIN").defaultTo(true).notNullable()
98
-                _Rank.forEach(r => table.boolean(r).defaultTo(false).notNullable())
99
-            }
100
-        },{
101
-            name: 'specs',
102
-            tableBuilder: (table) => {
103
-                table.increments("id")
104
-                table.string('class')
105
-                table.string('name')
100
+                _Rank.forEach(r => {
101
+                    if(r === 'ADMIN')
102
+                        table.boolean(r).defaultTo(true).notNullable()
103
+                    else
104
+                        table.boolean(r).defaultTo(false).notNullable()
105
+                })
106
             }
106
             }
107
         }
107
         }
108
         ,...this.exporters.flatMap(exp => exp['getTableDefinitions']?exp['getTableDefinitions']():undefined)
108
         ,...this.exporters.flatMap(exp => exp['getTableDefinitions']?exp['getTableDefinitions']():undefined)
109
     ]
109
     ]
110
 
110
 
111
     initialize = async () => {
111
     initialize = async () => {
112
+        this.exporters = [this.guild, this.item, this.raid, this.character] 
113
+
112
         //set up permissions
114
         //set up permissions
113
         await Promise.all( 
115
         await Promise.all( 
114
             [this, ...this.exporters].flatMap(exp => exp.exportRPCFeatures().map(async (feature) => {
116
             [this, ...this.exporters].flatMap(exp => exp.exportRPCFeatures().map(async (feature) => {
117
             }catch(e){}
119
             }catch(e){}
118
         })))
120
         })))
119
 
121
 
120
-        //initialize managed exporters
121
-        await Promise.all(this.exporters.map(ex => ex['initialize']?ex['initialize']():undefined))
122
-
123
-        //initialize spec table
124
-        await this.admin.knex('specs').insert(getSpecTableData()).catch(e => { console.log("skipping spec insertion") })
125
-
126
         //start rankServers
122
         //start rankServers
127
         const rankServers : any = {}   
123
         const rankServers : any = {}   
128
 
124
 
138
         }
134
         }
139
         this.rankServers = rankServers
135
         this.rankServers = rankServers
140
     
136
     
141
-        setInterval(this.checkExpiredSessions, 600_000)        
137
+        setInterval(this.checkExpiredSessions, 600_000)   
142
     }
138
     }
143
 
139
 
144
     checkExpiredSessions = () => {
140
     checkExpiredSessions = () => {
151
     }
147
     }
152
 
148
 
153
     checkConnection = async (socket: Socket) => {
149
     checkConnection = async (socket: Socket) => {
154
-        let data : Auth | false = false
150
+        let data : any = false
151
+        let tries = 0
155
         while(!data){
152
         while(!data){
153
+            tries ++
154
+            if(tries === 5){
155
+                socket.destroy()
156
+                return
157
+            }
156
             data = await Promise.race([socket.call('getUserData'), new Promise((res, rej) => { setTimeout(res, 250);})])
158
             data = await Promise.race([socket.call('getUserData'), new Promise((res, rej) => { setTimeout(res, 250);})])
157
         } 
159
         } 
158
         this.userLogins[data.user.name].connections[socket.port] = socket
160
         this.userLogins[data.user.name].connections[socket.port] = socket
181
     }
183
     }
182
 
184
 
183
     getRPCForRank = async (rank: Rank): Promise<AnyRPCExporter[]> => {
185
     getRPCForRank = async (rank: Rank): Promise<AnyRPCExporter[]> => {
184
-        return [
186
+        let rpcs = [
185
             ...this.exportRPCFeatures(), 
187
             ...this.exportRPCFeatures(), 
186
             ...this.exporters.flatMap((exp) => exp.exportRPCFeatures())
188
             ...this.exporters.flatMap((exp) => exp.exportRPCFeatures())
187
-        ].filter(async (feature) => await this.getPermission(<keyof FrontcraftFeatureIfc> feature.name, rank))
189
+        ]
190
+        
191
+        const bits = await  Promise.all(rpcs.map(async (feature) => {
192
+            const allowed = await this.getPermission(<keyof FrontcraftFeatureIfc> feature.name, rank)
193
+            return allowed
194
+        }))
195
+
196
+        return rpcs.filter(entry => bits.shift())
188
     }
197
     }
189
 
198
 
190
     createUser = async(user:User): Promise<User> => {
199
     createUser = async(user:User): Promise<User> => {
200
+        if(user.rank === 'ADMIN'){
201
+            const admins = await this.admin.knex
202
+                .select("*")
203
+                .from('users')
204
+                .where({rank: 'ADMIN'})
205
+
206
+            if(admins.length > 0){
207
+                return {} as User
208
+            }
209
+
210
+            user.locked = false
211
+        }
191
         await this.admin.knex('users')
212
         await this.admin.knex('users')
192
         .insert(user)
213
         .insert(user)
193
-        
214
+
194
         const users = await this.admin.knex
215
         const users = await this.admin.knex
195
         .select("*")
216
         .select("*")
196
         .from('users')
217
         .from('users')
197
         .where(user)
218
         .where(user)
219
+
198
         return users[0]
220
         return users[0]
199
     }
221
     }
200
 
222
 
238
                 port: this.rankServers[user.rank].port
260
                 port: this.rankServers[user.rank].port
239
             }
261
             }
240
 
262
 
241
-            this.userLogins[user.name] = {connections: {}, auth: userAuth}
263
+            this.userLogins[user.name] = {connections: {}, auth: userAuth, user:user}
242
             this.rankServers[user.rank].allowed.push(token.value)
264
             this.rankServers[user.rank].allowed.push(token.value)
243
 
265
 
244
             return userAuth 
266
             return userAuth 
247
         throw new Error('login failed')
269
         throw new Error('login failed')
248
     }
270
     }
249
 
271
 
272
+    getUserRecordByToken(tokenValue: string){
273
+        const maybeRecord = Object.values(this.userLogins).find(login => login.auth.token.value === tokenValue)
274
+        return maybeRecord?maybeRecord:undefined
275
+    }
276
+
250
     getAuth = async (tokenValue:string) : Promise<Auth> => {
277
     getAuth = async (tokenValue:string) : Promise<Auth> => {
251
-        const maybeAuth = Object.values(this.userLogins).find(login => login.auth.token.value === tokenValue)
278
+        const maybeAuth = this.getUserRecordByToken(tokenValue)
252
         if(maybeAuth)
279
         if(maybeAuth)
253
             return maybeAuth.auth
280
             return maybeAuth.auth
254
 
281
 

+ 16
- 4
src/backend/Components/User/RPCInterface.ts View File

1
-import { Token, Auth, User, RPCPermission, Rank } from "../../Types/Types"
1
+import { Auth, Rank, User, RPCPermission, Character } from "../../Types/Types"
2
+import { SpecT } from "../../Types/PlayerSpecs"
2
 
3
 
3
 export type LoginManagerIfc = {
4
 export type LoginManagerIfc = {
4
     Authenticator: {
5
     Authenticator: {
6
         logout: (username: string, tokenValue :string) => Promise<void>
7
         logout: (username: string, tokenValue :string) => Promise<void>
7
         getAuth: (tokenValue: string) => Promise<Auth>
8
         getAuth: (tokenValue: string) => Promise<Auth>
8
         checkToken: (token: string, rank: Rank) => Promise<boolean>
9
         checkToken: (token: string, rank: Rank) => Promise<boolean>
10
+        createUser: (user:User) => Promise<User>
9
     }
11
     }
10
 }
12
 }
11
 
13
 
12
 export type LoginManagerFeatureIfc = {
14
 export type LoginManagerFeatureIfc = {
13
-    createUser: {
14
-        createUser: (user:User) => Promise<User>
15
-    }
16
     modifyPermissions: {
15
     modifyPermissions: {
17
         setPermission: (perm: RPCPermission) => Promise<void>
16
         setPermission: (perm: RPCPermission) => Promise<void>
18
         getPermissions: () => Promise<RPCPermission[]>
17
         getPermissions: () => Promise<RPCPermission[]>
19
     }
18
     }
19
+}
20
+
21
+export type CharacterManagerIfc = {
22
+    CharacterManager: {
23
+        getSpecId : <c extends keyof SpecT>(clazz: c, name: SpecT[c]) => Promise<number>
24
+        getCharacters : () => Promise<Character[]>
25
+    }
26
+}
27
+
28
+export type CharacterManagerFeatureIfc = {
29
+    createCharacter: {
30
+        createCharacter: (usertoken: string, char : Character) => Promise<Character>
31
+    }
20
 }
32
 }

+ 50
- 0
src/backend/Injector/Injector.ts View File

1
+import 'reflect-metadata';
2
+import { Type } from './Util';
3
+import { FrontworkComponent } from '../Types/FrontworkComponent';
4
+
5
+
6
+/**
7
+ * The Injector stores services and resolves requested instances.
8
+ */
9
+export const Injector = new class {
10
+
11
+  injectionQueue :any[] = []
12
+
13
+  rootInterface : Type<any>
14
+  root : Type<any>
15
+  rootModules : Type<any>[] = []
16
+
17
+  moduleObjs : {[key in string] : FrontworkComponent} = {}
18
+
19
+  /**
20
+   * Resolves instances by injecting required services
21
+   * @param {Type<any>} target
22
+   * @returns {T}
23
+   */
24
+  resolve<T>(target: Type<any>): T {
25
+    // tokens are required dependencies, while injections are resolved tokens from the Injector
26
+
27
+    if(this.moduleObjs[target.name])
28
+      return this.moduleObjs[target.name] as any
29
+
30
+    if(target.name === this.rootInterface.name || target.name === this.root.name){
31
+      let modules = this.rootModules.map(m => {
32
+        const module = new m()
33
+        this.moduleObjs[m.name] = module
34
+        return module
35
+      })
36
+      const rootobj = new this.root(modules);
37
+
38
+      this.moduleObjs[this.rootInterface.name] = rootobj
39
+      this.moduleObjs[target.name] = rootobj
40
+      this.injectionQueue.forEach(i => {
41
+        i.target[i.where] = this.moduleObjs[i.what.name]
42
+      })
43
+      return rootobj
44
+    }
45
+    this.moduleObjs[target.name] = new target()
46
+    return this.moduleObjs[target.name] as any
47
+    
48
+    
49
+  }
50
+};

+ 34
- 0
src/backend/Injector/ServiceDecorator.ts View File

1
+import { Injector } from "./Injector";
2
+import { Type, GenericClassDecorator } from "./Util";
3
+import { FrontworkComponent } from "../Types/FrontworkComponent";
4
+
5
+/**
6
+ * @returns {GenericClassDecorator<Type<any>>}
7
+ * @constructor
8
+ */
9
+export const Module = (...args) : GenericClassDecorator<Type<any>> => {
10
+  return (target: Type<any>) => {
11
+    Injector.rootModules.push(target)
12
+  }
13
+}
14
+
15
+/**
16
+ * @returns {GenericClassDecorator<Type<any>>}
17
+ * @constructor
18
+ */
19
+export const RootComponent = (config : {
20
+    rootInterface : Type<any>
21
+    imports : Type<FrontworkComponent>[]
22
+  }) : GenericClassDecorator<Type<any>> => {
23
+  return (target: Type<any>) => {
24
+    Injector.rootModules = config.imports
25
+    Injector.rootInterface = config.rootInterface
26
+    Injector.root = target
27
+  }
28
+}
29
+
30
+export const Inject = (type: any) => {
31
+  return function (_this, key) {
32
+    Injector.injectionQueue.push({what: type, target: _this, where:key})
33
+  }
34
+}

+ 11
- 0
src/backend/Injector/Util.ts View File

1
+/**
2
+ * Type for what object is instances of
3
+ */
4
+export interface Type<T> {
5
+  new(...args: any[]): T;
6
+}
7
+
8
+/**
9
+ * Generic `ClassDecorator` type
10
+ */
11
+export type GenericClassDecorator<T> = (target: T) => void;

+ 3
- 21
src/backend/Launcher.ts View File

1
-import { FrontworkAdmin } from './Admin/Admin'
2
-import { RaidManager } from "./Components/Raid/RaidManager";
3
-import { ItemManager } from "./Components/Item/ItemManager";
4
-import { LoginManager } from "./Components/User/LoginManager";
5
-import { Debugger } from './Components/Debugger/Debugger';
6
-import { FrontworkComponent } from './Types/FrontworkComponent';
7
-import { GuildManager } from './Components/Guild/GuildManager';
1
+import { Injector } from './Injector/Injector';
2
+import { IAdmin } from './Admin/Interface';
8
 require('events').EventEmitter.defaultMaxListeners = 0;
3
 require('events').EventEmitter.defaultMaxListeners = 0;
9
 
4
 
10
-let raidManager = new RaidManager()
11
-let itemManager = new ItemManager()
12
-let guildManager = new GuildManager()
13
-let loginManager = new LoginManager([
14
-    raidManager,
15
-    itemManager,
16
-    guildManager
17
-])
18
-
19
-let components:FrontworkComponent[] = [ guildManager, raidManager, itemManager, loginManager ]
20
-let dbg = new Debugger(components)
21
-
22
-
23
-new FrontworkAdmin([dbg, ...components]).start()
5
+Injector.resolve<IAdmin>(IAdmin).start()

+ 1
- 4
src/backend/Types/FrontworkComponent.ts View File

1
-import { PrivilegedRPCExporter } from "./PrivilegedRPCExporter";
2
 import { RPCInterface, RPCExporter, RPCInterfaceArray } from "rpclibrary";
1
 import { RPCInterface, RPCExporter, RPCInterfaceArray } from "rpclibrary";
2
+import { PrivilegedRPCExporter } from "./PrivilegedRPCExporter";
3
 import { TableDefinitionExporter } from "./Interfaces";
3
 import { TableDefinitionExporter } from "./Interfaces";
4
-import { FrontworkAdmin } from "../Admin/Admin";
5
 import { TableDefiniton } from "./Types";
4
 import { TableDefiniton } from "./Types";
6
 
5
 
7
 export interface FrontworkComponent<
6
 export interface FrontworkComponent<
14
     PrivilegedRPCExporter<Ifc, FeatureIfc, Name, FeatureName, SubresT>,
13
     PrivilegedRPCExporter<Ifc, FeatureIfc, Name, FeatureName, SubresT>,
15
     TableDefinitionExporter
14
     TableDefinitionExporter
16
 {
15
 {
17
-    admin:FrontworkAdmin
18
     name: Name;
16
     name: Name;
19
 
17
 
20
     exportRPCFeatures(): RPCExporter<FeatureIfc, FeatureName, SubresT>[] 
18
     exportRPCFeatures(): RPCExporter<FeatureIfc, FeatureName, SubresT>[] 
22
     getTableDefinitions(): TableDefiniton[] 
20
     getTableDefinitions(): TableDefiniton[] 
23
 
21
 
24
     initialize?(): Promise<any>
22
     initialize?(): Promise<any>
25
-    onSetAdmin?(admin:FrontworkAdmin): void
26
 }
23
 }

+ 14
- 2
src/backend/Types/PlayerSpecs.ts View File

1
-import { Class, _Class, Spec } from "./Types";
1
+import { Spec, _Class } from "./Types"
2
 
2
 
3
-const specs : { [classname in Class] : string[] } = {
3
+export type SpecT = {
4
+    Warrior : 'Arms' | 'Fury' | 'Protection'
5
+    Rogue: 'Subetly' | 'Combat' | 'Assassination'
6
+    Hunter: 'Beast Mastery' | 'Marksmanship' | 'Survival'
7
+    Paladin: 'Holy' | 'Protection' | 'Retribution'
8
+    Priest: 'Discipline' | 'Holy' | 'Shadow'
9
+    Druid: 'Feral (Tank)' | 'Feral (DPS)' | 'Restoration' | 'Balance'
10
+    Mage: 'Frost' | 'Arcane' | 'Fire'
11
+    Warlock: 'Demonology' | 'Destruction' | 'Affliction'
12
+    Shaman: 'Restoration' | 'Enhancement' | 'Elemental'
13
+}
14
+
15
+export const specs : { [classname in keyof SpecT] : SpecT[classname][] } = {
4
     Warrior : [
16
     Warrior : [
5
         'Arms',
17
         'Arms',
6
         'Fury',
18
         'Fury',

+ 4
- 3
src/backend/Types/Plugin.ts View File

1
+import { RPCExporter, RPC } from "rpclibrary"
2
+import { ConfigExporter } from "loadson"
3
+import { TableDefinitionExporter } from "./Interfaces"
1
 import { FrontworkAdmin } from "../Admin/Admin"
4
 import { FrontworkAdmin } from "../Admin/Admin"
2
-import { RPC, RPCExporter } from "rpclibrary"
3
 import { TableDefiniton } from "./Types"
5
 import { TableDefiniton } from "./Types"
4
-import { TableDefinitionExporter } from "./Interfaces"
5
-import { ConfigExporter } from "loadson"
6
+
6
 
7
 
7
 export abstract class Plugin<ConfType = {}> 
8
 export abstract class Plugin<ConfType = {}> 
8
 implements ConfigExporter<ConfType>, RPCExporter<any,any,any>, TableDefinitionExporter{
9
 implements ConfigExporter<ConfType>, RPCExporter<any,any,any>, TableDefinitionExporter{

+ 14
- 6
src/backend/Types/Types.ts View File

1
 import * as Knex from "knex"
1
 import * as Knex from "knex"
2
 import { RPCExporter } from "rpclibrary";
2
 import { RPCExporter } from "rpclibrary";
3
-import { RaidManagerFeatureIfc } from "../Components/Raid/RPCInterface";
4
-import { LoginManagerIfc, LoginManagerFeatureIfc } from "../Components/User/RPCInterface";
3
+import { RaidManagerIfc, RaidManagerFeatureIfc } from "../Components/Raid/RPCInterface";
4
+import { LoginManagerIfc, CharacterManagerIfc, LoginManagerFeatureIfc, CharacterManagerFeatureIfc } from "../Components/User/RPCInterface";
5
 
5
 
6
 
6
 
7
 export declare type NotificationSeverity = 'Info' | 'Important' | 'Error';
7
 export declare type NotificationSeverity = 'Info' | 'Important' | 'Error';
34
     id?: number
34
     id?: number
35
     name: string
35
     name: string
36
     pwhash: string
36
     pwhash: string
37
-    specid: number
38
     rank: Rank
37
     rank: Rank
39
     email?: string
38
     email?: string
39
+    locked: boolean
40
 }
40
 }
41
 
41
 
42
 export type Raid = {
42
 export type Raid = {
52
     user_id: number
52
     user_id: number
53
 }
53
 }
54
 
54
 
55
+export type Character = {
56
+    id? : number
57
+    name : string
58
+    specid : number
59
+    userid : number
60
+}
61
+
55
 export type Token = {
62
 export type Token = {
56
     value: string
63
     value: string
57
     user_id: number
64
     user_id: number
60
 
67
 
61
 export type Auth = {port: number, user: User, token: Token}
68
 export type Auth = {port: number, user: User, token: Token}
62
 
69
 
63
-export type FrontcraftIfc = LoginManagerIfc 
64
-                          //& ItemManagerIfc
70
+export type FrontcraftIfc = RaidManagerIfc
71
+                          & LoginManagerIfc
72
+                          & CharacterManagerIfc
65
 
73
 
66
 export type FrontcraftFeatureIfc = RaidManagerFeatureIfc 
74
 export type FrontcraftFeatureIfc = RaidManagerFeatureIfc 
67
                                  & LoginManagerFeatureIfc
75
                                  & LoginManagerFeatureIfc
68
-                                 //& ItemManagerFeatureIfc
76
+                                 & CharacterManagerFeatureIfc
69
 
77
 
70
 export type Spec = {
78
 export type Spec = {
71
     id?: number,
79
     id?: number,

+ 3
- 3
src/frontend/package-lock.json View File

14269
       "integrity": "sha512-ZYzRkETgBrdEGzL5JSKimvjI2CX7ioyZCkX2BpcfyjqI+079W0wHAyj5W4rIZMcDSOHgLZtgz1IdDi/vU77KEQ=="
14269
       "integrity": "sha512-ZYzRkETgBrdEGzL5JSKimvjI2CX7ioyZCkX2BpcfyjqI+079W0wHAyj5W4rIZMcDSOHgLZtgz1IdDi/vU77KEQ=="
14270
     },
14270
     },
14271
     "rpclibrary": {
14271
     "rpclibrary": {
14272
-      "version": "1.5.1",
14273
-      "resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.5.1.tgz",
14274
-      "integrity": "sha512-EN6wlifkFmEQrHhtbalS0i90ZBNbLNFcrQ8hTrcJLBuNMFab49R8i5fruoDLDJM88iPcx6eWccI6zLHK7Qkl2A==",
14272
+      "version": "1.6.2",
14273
+      "resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.6.2.tgz",
14274
+      "integrity": "sha512-lQTU4XkB9CSHz7YgtAcpVfyR5XrmTRX4P4eQjK6DDUjqKSFvJb5ChXjHnt1BcaNWbJ2VqmhCNVbcoyunJ2u7Rg==",
14275
       "requires": {
14275
       "requires": {
14276
         "bsock": "^0.1.9",
14276
         "bsock": "^0.1.9",
14277
         "http": "0.0.0",
14277
         "http": "0.0.0",

+ 1
- 1
src/frontend/package.json View File

69
     "normalize.css": "6.0.0",
69
     "normalize.css": "6.0.0",
70
     "pace-js": "1.0.2",
70
     "pace-js": "1.0.2",
71
     "roboto-fontface": "0.8.0",
71
     "roboto-fontface": "0.8.0",
72
-    "rpclibrary": "^1.5.1",
72
+    "rpclibrary": "^1.6.2",
73
     "rxjs": "6.5.2",
73
     "rxjs": "6.5.2",
74
     "rxjs-compat": "6.3.0",
74
     "rxjs-compat": "6.3.0",
75
     "socicon": "3.0.5",
75
     "socicon": "3.0.5",

+ 1
- 3
src/frontend/src/app/app.component.ts View File

19
 
19
 
20
   ngOnInit(): void {
20
   ngOnInit(): void {
21
     this.analytics.trackPageViews();
21
     this.analytics.trackPageViews();
22
-    this.loginSvc.getFeature('createUser').then( (f) => {
23
-     
24
-    })
22
+ 
25
     window['s'] = this.loginSvc
23
     window['s'] = this.loginSvc
26
   }
24
   }
27
 }
25
 }

+ 24
- 8
src/frontend/src/app/frontcraft/auth/register/register.component.html View File

1
 <h1 id="title" class="title">Account application</h1>
1
 <h1 id="title" class="title">Account application</h1>
2
 
2
 
3
-<form (ngSubmit)="register()" #form="ngForm" aria-labelledby="title">
3
+<form (ngSubmit)="onSubmit()" #form="ngForm" aria-labelledby="title">
4
 
4
 
5
   <div class="form-control-group">
5
   <div class="form-control-group">
6
     <label class="label" for="input-email">Email address:</label>
6
     <label class="label" for="input-email">Email address:</label>
36
     <label class="label" for="input-password">Password:</label>
36
     <label class="label" for="input-password">Password:</label>
37
     <input nbInput
37
     <input nbInput
38
            fullWidth
38
            fullWidth
39
-           [(ngModel)]="user.password"
39
+           [(ngModel)]="user.pwhash"
40
            #password="ngModel"
40
            #password="ngModel"
41
            name="password"
41
            name="password"
42
            type="password"
42
            type="password"
58
     <nb-card-body>
58
     <nb-card-body>
59
       <nb-checkbox [(ngModel)]="showApplication" name="amMember" #checkbox>I am already a member</nb-checkbox>
59
       <nb-checkbox [(ngModel)]="showApplication" name="amMember" #checkbox>I am already a member</nb-checkbox>
60
       <br />
60
       <br />
61
+      
61
       <span *ngIf="showApplication">
62
       <span *ngIf="showApplication">
62
-        And my main is &nbsp; <input name="preMember" nbInput> with rank <nb-select placeholder="Rank">
63
-          <nb-option *ngFor="let rank of ranks" [value]=rank >{{rank}}</nb-option>
64
-          
63
+        And my main is &nbsp; <input name="preMember" [(ngModel)]="character.name"  nbInput>, a 
64
+        <nb-select [(selected)]="character.spec" placeholder="Spec" (selectedChange)="onSelectSpec()">
65
+          <nb-option *ngFor="let spec of specs" [value]="spec">{{spec}}</nb-option>
66
+        </nb-select>
67
+        <nb-select [(selected)]="character.class" placeholder="Class" (selectedChange)="onSelectClass()">
68
+          <nb-option *ngFor="let class of classes"  [value]="class">{{class}}</nb-option>
69
+        </nb-select>
70
+         with rank 
71
+        <nb-select [(selected)]="user.rank" placeholder="Rank">
72
+          <nb-option *ngFor="let rank of ranks" [value]="rank" >{{rank}}</nb-option>
65
         </nb-select>
73
         </nb-select>
66
       </span>
74
       </span>
67
-      <span *ngIf="!showApplication">Hello my name is &nbsp; <input name="charName" nbInput>
68
-        I am playing a level 60  <input name="charName" placeholder="Spec + Class" nbInput> and I would like to join tranquil because
75
+
76
+      <span *ngIf="!showApplication">Hello my name is &nbsp; <input name="charName" [(ngModel)]="character.name" nbInput>
77
+        I am playing a level 60 
78
+        <nb-select [(selected)]="character.spec" placeholder="Spec" (selectedChange)="onSelectSpec()">
79
+          <nb-option *ngFor="let spec of specs" [value]="spec">{{spec}}</nb-option>
80
+        </nb-select>
81
+        <nb-select [(selected)]="character.class" placeholder="Class" (selectedChange)="onSelectClass()">
82
+          <nb-option *ngFor="let class of classes" [value]="class">{{class}}</nb-option>
83
+        </nb-select>
84
+        and I would like to join Tranquil because
69
         <textarea nbInput fullWidth placeholder="reason" style="min-height: 400px"></textarea>
85
         <textarea nbInput fullWidth placeholder="reason" style="min-height: 400px"></textarea>
70
 
86
 
71
       </span>
87
       </span>
79
           size="giant"
95
           size="giant"
80
           [disabled]="submitted || !form.valid"
96
           [disabled]="submitted || !form.valid"
81
           [class.btn-pulse]="submitted">
97
           [class.btn-pulse]="submitted">
82
-    Log In
98
+    Register
83
   </button>
99
   </button>
84
 </form>
100
 </form>
85
 
101
 

+ 44
- 7
src/frontend/src/app/frontcraft/auth/register/register.component.ts View File

1
 import { Component, OnInit } from '@angular/core';
1
 import { Component, OnInit } from '@angular/core';
2
-import { LoginApiService } from '../../services/login-api';
2
+import { LoginApiService, hash } from '../../services/login-api';
3
 import { Router } from '@angular/router';
3
 import { Router } from '@angular/router';
4
-import { _Rank } from '../../../../../../backend/Types/Types'
4
+import { _Rank, _Class, Class, User  } from '../../../../../../backend/Types/Types'
5
+import { specs  } from '../../../../../../backend/Types/PlayerSpecs'
6
+
5
 
7
 
6
 @Component({
8
 @Component({
7
   selector: 'register',
9
   selector: 'register',
9
 })
11
 })
10
 export class RegisterComponent implements OnInit{
12
 export class RegisterComponent implements OnInit{
11
 
13
 
12
-  user: any = {};
13
-  showApplication = false
14
+  user = {
15
+    rank: "Guest"
16
+  } as User
17
+
18
+  character: any = {
19
+    class : "Warrior",
20
+    spec : "Arms"
21
+  }
22
+
23
+
14
   ranks = _Rank
24
   ranks = _Rank
25
+  classes = _Class
26
+  selectedClass : Class = "Warrior"
27
+  selectedSpec = specs[this.selectedClass][0]
28
+  specs = specs[this.selectedClass]
29
+  showApplication = false
15
 
30
 
16
   constructor(
31
   constructor(
17
     private router : Router,  
32
     private router : Router,  
23
       if(loggedin){
38
       if(loggedin){
24
         this.router.navigateByUrl("/")
39
         this.router.navigateByUrl("/")
25
       }
40
       }
26
-    });
41
+    })
27
   }
42
   }
28
 
43
 
29
-  login(){
30
-    this.loginApi.login(this.user.name, this.user.password)
44
+  onSelectClass(){
45
+    this.specs = specs[this.character.class]
46
+    setTimeout(() => {
47
+      this.character.spec = this.specs[0]
48
+    }, 25)
31
   }
49
   }
50
+
51
+  onSelectSpec(){
52
+  }
53
+
54
+  async onSubmit(){
55
+    this.user.pwhash = await hash(this.user.pwhash)
56
+    const user = this.user
57
+    this.user = {} as User
58
+    const char = this.character
59
+    this.character = {}
60
+
61
+    try{
62
+      const usr = await this.loginApi.getUnprivilegedSocket().Authenticator.createUser(user)
63
+      
64
+    }catch(e){
65
+      alert("Error creating user"+e)
66
+    }
67
+  }
68
+
32
 }
69
 }

+ 8
- 5
src/frontend/src/app/frontcraft/services/login-api.ts View File

65
     getCurrentUser = () : User | undefined => this.auth?this.auth.user:undefined
65
     getCurrentUser = () : User | undefined => this.auth?this.auth.user:undefined
66
 
66
 
67
     login = async (username: string, password: string) : Promise<RPCSocket & SomeOf<FrontcraftFeatureIfc>> => {
67
     login = async (username: string, password: string) : Promise<RPCSocket & SomeOf<FrontcraftFeatureIfc>> => {
68
-        const buf = str2arraybuf(password)
69
-        const pwHash = await crypto.subtle.digest('SHA-256', buf);
70
-
71
-        const auth = await this.socket.Authenticator.login(username, buf2hex(pwHash))
72
-
68
+        const pwHash = await hash(password)
69
+        const auth = await this.socket.Authenticator.login(username, pwHash)
73
 
70
 
74
         if(!auth){ 
71
         if(!auth){ 
75
             await this.logout()
72
             await this.logout()
129
     return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
126
     return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
130
 }
127
 }
131
 
128
 
129
+export async function hash(value:string) : Promise<string>{
130
+    const buf = str2arraybuf(value)
131
+    const pwHash = await crypto.subtle.digest('SHA-256', buf);
132
+    return buf2hex(pwHash)
133
+}
134
+
132
 //angular depenency manager requires this
135
 //angular depenency manager requires this
133
 export function initializeLoginSvc(svc: LoginApiService): () => Promise<any> {
136
 export function initializeLoginSvc(svc: LoginApiService): () => Promise<any> {
134
     return svc.initialize
137
     return svc.initialize

+ 2
- 2
src/frontend/tsconfig.json View File

9
     "moduleResolution": "node",
9
     "moduleResolution": "node",
10
     "emitDecoratorMetadata": true,
10
     "emitDecoratorMetadata": true,
11
     "experimentalDecorators": true,
11
     "experimentalDecorators": true,
12
-    "target": "es2015",
12
+    "target": "es5",
13
     "typeRoots": [
13
     "typeRoots": [
14
       "node_modules/@types"
14
       "node_modules/@types"
15
     ],
15
     ],
16
     "lib": [
16
     "lib": [
17
-      "es2017",
17
+      "es2019",
18
       "dom"
18
       "dom"
19
     ],
19
     ],
20
     "plugins": [
20
     "plugins": [

+ 4
- 3
tsconfig.json View File

7
       "declaration": true,
7
       "declaration": true,
8
       "outDir": "./lib",
8
       "outDir": "./lib",
9
       "strict": true,
9
       "strict": true,
10
-      "experimentalDecorators": true
10
+      "experimentalDecorators": true,
11
+      "emitDecoratorMetadata": true
11
     },
12
     },
12
-    "include": ["src/backend/**/*"],
13
-    "exclude": ["node_modules", "**/__tests__/*"],
13
+    "include": ["src/backend/**/*", "test/**/*"],
14
+    "exclude": ["node_modules", "**/__tests__/*"]
14
 }
15
 }

Loading…
Cancel
Save