浏览代码

Added dependency injection

master
peter 5 年前
父节点
当前提交
e4a6972884

+ 1262
- 43
package-lock.json
文件差异内容过多而无法显示
查看文件


+ 8
- 2
package.json 查看文件

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

+ 30
- 14
src/backend/Admin/Admin.ts 查看文件

@@ -3,19 +3,37 @@
3 3
 import { getLogger } from 'frontblock-generic/Types';
4 4
 import { promises as fs, mkdirSync } from "fs"
5 5
 import { RPCServer } from 'rpclibrary'
6
-import { AdminConf, TableDefiniton } from '../Types/Types';
7
-import { RPCConfigLoader } from '../Components/RPCConfigLoader';
8 6
 import * as Path from 'path'
9 7
 import * as Knex from  'knex';
10 8
 import * as http from 'http';
11 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 16
 import { TableDefinitionExporter } from '../Types/Interfaces';
17
+import { AdminConf, TableDefiniton } from '../Types/Types';
18
+import { RPCConfigLoader } from '../Components/RPCConfigLoader';
13 19
 import { FrontworkComponent } from '../Types/FrontworkComponent';
20
+import { IAdmin } from './Interface';
21
+
14 22
 
15 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 35
 export class FrontworkAdmin 
18
-implements TableDefinitionExporter {
36
+implements TableDefinitionExporter, IAdmin {
19 37
     knex:Knex
20 38
     config: RPCConfigLoader<AdminConf>
21 39
     rpcServer: RPCServer
@@ -23,7 +41,7 @@ implements TableDefinitionExporter {
23 41
     private express
24 42
     private httpServer
25 43
 
26
-    constructor(private components: FrontworkComponent[]){
44
+    constructor(private frontworkComponents: FrontworkComponent[] = []){
27 45
         this.config = new RPCConfigLoader<AdminConf>({
28 46
             name: "FrontworkAdminConf", 
29 47
             getDefaultConfig: () => {
@@ -40,19 +58,17 @@ implements TableDefinitionExporter {
40 58
                 }   
41 59
             }
42 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 63
     async start(){
51 64
         await this.makeKnex()
52 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 67
         this.startWebserver()
55
-        
68
+    }
69
+
70
+    stop(){
71
+        process.exit(0);
56 72
     }
57 73
 
58 74
     protected configChangeHandler = (conf:AdminConf, key?:string) => {
@@ -71,13 +87,13 @@ implements TableDefinitionExporter {
71 87
 
72 88
     getTableDefinitions(): TableDefiniton[]{
73 89
         return [
74
-            ...this.components
90
+            ...this.frontworkComponents
75 91
         ].flatMap(exporter => exporter.getTableDefinitions())
76 92
     }
77 93
 
78 94
     private startWebsocket(){
79 95
         this.rpcServer = new RPCServer(20000, [
80
-            ...this.components,
96
+            ...this.frontworkComponents,
81 97
         ])
82 98
     }
83 99
 
@@ -169,4 +185,4 @@ process.on( 'SIGINT', function() {
169 185
     logger.info("Shutting down from SIGINT (Ctrl-C)" );
170 186
     // some other closing procedures go here
171 187
     process.exit(0);
172
-})
188
+})

+ 13
- 0
src/backend/Admin/Interface.ts 查看文件

@@ -0,0 +1,13 @@
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 查看文件

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

+ 18
- 10
src/backend/Components/Item/ItemManager.ts 查看文件

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

+ 6
- 3
src/backend/Components/Raid/RPCInterface.ts 查看文件

@@ -1,7 +1,10 @@
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 9
 export type RaidManagerFeatureIfc = {
7 10
     manageRaid: {

+ 17
- 11
src/backend/Components/Raid/RaidManager.ts 查看文件

@@ -1,14 +1,22 @@
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 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 9
 export class RaidManager
7 10
 implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>{
8 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 21
     exportRPCFeatures() {
14 22
         return [{
@@ -26,9 +34,6 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>{
26 34
         },{
27 35
             name: 'signup' as 'signup',
28 36
             exportRPCs: () => [{
29
-                name: 'getRaids' as 'getRaids',
30
-                call: this.getRaids
31
-            },{
32 37
                 name: 'getSingups' as 'getSingups',
33 38
                 call: this.getSignups
34 39
             },{
@@ -52,9 +57,10 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>{
52 57
             },{
53 58
                 name: 'signups',
54 59
                 tableBuilder: (table) => {
55
-                    table.integer('raid_id').primary()
60
+                    table.primary(['raid_id', 'user_id'])
61
+                    table.integer('raid_id')
56 62
                     table.foreign('raid_id').references('id').inTable('raids')
57
-                    table.integer('user_id').primary()
63
+                    table.integer('user_id')
58 64
                     table.foreign('user_id').references('id').inTable('users')
59 65
                 }
60 66
             }            
@@ -77,7 +83,7 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>{
77 83
     })
78 84
     .delete()
79 85
 
80
-    getRaids = async () => await this.admin.knex
86
+    getRaids = async () : Promise<Raid[]> => await this.admin.knex
81 87
     .select('*')
82 88
     .from('raids')
83 89
     

+ 96
- 0
src/backend/Components/User/CharacterManager.ts 查看文件

@@ -0,0 +1,96 @@
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 查看文件

@@ -1,10 +1,15 @@
1 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 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 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 13
 const uuid = require('uuid/v4')
9 14
 
10 15
 const ONE_WEEK = 604800000 
@@ -15,21 +20,35 @@ type Serverstate = {
15 20
     allowed: string[]
16 21
 }
17 22
 
23
+
24
+@Module()
18 25
 export class LoginManager
19 26
 implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>{
20 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 45
     rankServers : {[rank in Rank] : Serverstate}
24 46
     userLogins : {[username in string] : {
47
+        user: User
25 48
         connections: {[port in number]: Socket}
26 49
         auth: Auth
27 50
     }} = {}
28 51
 
29
-    constructor(
30
-        private exporters: PrivilegedRPCExporter[]
31
-    ){}
32
-
33 52
     exportRPCs = () => [
34 53
         {
35 54
             name: 'login' as 'login',
@@ -43,21 +62,14 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>{
43 62
         },{
44 63
             name: 'checkToken' as 'checkToken',
45 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 71
     exportRPCFeatures = () => [
54 72
         {
55
-            name: 'createUser' as 'createUser',
56
-            exportRPCs: () => [{
57
-                name: 'createUser' as 'createUser',
58
-                call: this.createUser
59
-            }]
60
-        },{
61 73
             name: 'modifyPermissions' as 'modifyPermissions',
62 74
             exportRPCs: () => [{
63 75
                 name: 'getPermissions' as 'getPermissions',
@@ -79,36 +91,26 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>{
79 91
                 table.string("pwhash").notNullable()
80 92
                 table.string("rank").notNullable()
81 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 97
             name: 'rpcpermissions',
95 98
             tableBuilder: (table) => {
96 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 108
         ,...this.exporters.flatMap(exp => exp['getTableDefinitions']?exp['getTableDefinitions']():undefined)
109 109
     ]
110 110
 
111 111
     initialize = async () => {
112
+        this.exporters = [this.guild, this.item, this.raid, this.character] 
113
+
112 114
         //set up permissions
113 115
         await Promise.all( 
114 116
             [this, ...this.exporters].flatMap(exp => exp.exportRPCFeatures().map(async (feature) => {
@@ -117,12 +119,6 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>{
117 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 122
         //start rankServers
127 123
         const rankServers : any = {}   
128 124
 
@@ -138,7 +134,7 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>{
138 134
         }
139 135
         this.rankServers = rankServers
140 136
     
141
-        setInterval(this.checkExpiredSessions, 600_000)        
137
+        setInterval(this.checkExpiredSessions, 600_000)   
142 138
     }
143 139
 
144 140
     checkExpiredSessions = () => {
@@ -151,8 +147,14 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>{
151 147
     }
152 148
 
153 149
     checkConnection = async (socket: Socket) => {
154
-        let data : Auth | false = false
150
+        let data : any = false
151
+        let tries = 0
155 152
         while(!data){
153
+            tries ++
154
+            if(tries === 5){
155
+                socket.destroy()
156
+                return
157
+            }
156 158
             data = await Promise.race([socket.call('getUserData'), new Promise((res, rej) => { setTimeout(res, 250);})])
157 159
         } 
158 160
         this.userLogins[data.user.name].connections[socket.port] = socket
@@ -181,20 +183,40 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>{
181 183
     }
182 184
 
183 185
     getRPCForRank = async (rank: Rank): Promise<AnyRPCExporter[]> => {
184
-        return [
186
+        let rpcs = [
185 187
             ...this.exportRPCFeatures(), 
186 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 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 212
         await this.admin.knex('users')
192 213
         .insert(user)
193
-        
214
+
194 215
         const users = await this.admin.knex
195 216
         .select("*")
196 217
         .from('users')
197 218
         .where(user)
219
+
198 220
         return users[0]
199 221
     }
200 222
 
@@ -238,7 +260,7 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>{
238 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 264
             this.rankServers[user.rank].allowed.push(token.value)
243 265
 
244 266
             return userAuth 
@@ -247,8 +269,13 @@ implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>{
247 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 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 279
         if(maybeAuth)
253 280
             return maybeAuth.auth
254 281
 

+ 16
- 4
src/backend/Components/User/RPCInterface.ts 查看文件

@@ -1,4 +1,5 @@
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 4
 export type LoginManagerIfc = {
4 5
     Authenticator: {
@@ -6,15 +7,26 @@ export type LoginManagerIfc = {
6 7
         logout: (username: string, tokenValue :string) => Promise<void>
7 8
         getAuth: (tokenValue: string) => Promise<Auth>
8 9
         checkToken: (token: string, rank: Rank) => Promise<boolean>
10
+        createUser: (user:User) => Promise<User>
9 11
     }
10 12
 }
11 13
 
12 14
 export type LoginManagerFeatureIfc = {
13
-    createUser: {
14
-        createUser: (user:User) => Promise<User>
15
-    }
16 15
     modifyPermissions: {
17 16
         setPermission: (perm: RPCPermission) => Promise<void>
18 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 查看文件

@@ -0,0 +1,50 @@
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 查看文件

@@ -0,0 +1,34 @@
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 查看文件

@@ -0,0 +1,11 @@
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 查看文件

@@ -1,23 +1,5 @@
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 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 查看文件

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

+ 14
- 2
src/backend/Types/PlayerSpecs.ts 查看文件

@@ -1,6 +1,18 @@
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 16
     Warrior : [
5 17
         'Arms',
6 18
         'Fury',

+ 4
- 3
src/backend/Types/Plugin.ts 查看文件

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

+ 14
- 6
src/backend/Types/Types.ts 查看文件

@@ -1,7 +1,7 @@
1 1
 import * as Knex from "knex"
2 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 7
 export declare type NotificationSeverity = 'Info' | 'Important' | 'Error';
@@ -34,9 +34,9 @@ export type User = {
34 34
     id?: number
35 35
     name: string
36 36
     pwhash: string
37
-    specid: number
38 37
     rank: Rank
39 38
     email?: string
39
+    locked: boolean
40 40
 }
41 41
 
42 42
 export type Raid = {
@@ -52,6 +52,13 @@ export type Signup = {
52 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 62
 export type Token = {
56 63
     value: string
57 64
     user_id: number
@@ -60,12 +67,13 @@ export type Token = {
60 67
 
61 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 74
 export type FrontcraftFeatureIfc = RaidManagerFeatureIfc 
67 75
                                  & LoginManagerFeatureIfc
68
-                                 //& ItemManagerFeatureIfc
76
+                                 & CharacterManagerFeatureIfc
69 77
 
70 78
 export type Spec = {
71 79
     id?: number,

+ 3
- 3
src/frontend/package-lock.json 查看文件

@@ -14269,9 +14269,9 @@
14269 14269
       "integrity": "sha512-ZYzRkETgBrdEGzL5JSKimvjI2CX7ioyZCkX2BpcfyjqI+079W0wHAyj5W4rIZMcDSOHgLZtgz1IdDi/vU77KEQ=="
14270 14270
     },
14271 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 14275
       "requires": {
14276 14276
         "bsock": "^0.1.9",
14277 14277
         "http": "0.0.0",

+ 1
- 1
src/frontend/package.json 查看文件

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

+ 1
- 3
src/frontend/src/app/app.component.ts 查看文件

@@ -19,9 +19,7 @@ export class AppComponent implements OnInit {
19 19
 
20 20
   ngOnInit(): void {
21 21
     this.analytics.trackPageViews();
22
-    this.loginSvc.getFeature('createUser').then( (f) => {
23
-     
24
-    })
22
+ 
25 23
     window['s'] = this.loginSvc
26 24
   }
27 25
 }

+ 24
- 8
src/frontend/src/app/frontcraft/auth/register/register.component.html 查看文件

@@ -1,6 +1,6 @@
1 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 5
   <div class="form-control-group">
6 6
     <label class="label" for="input-email">Email address:</label>
@@ -36,7 +36,7 @@
36 36
     <label class="label" for="input-password">Password:</label>
37 37
     <input nbInput
38 38
            fullWidth
39
-           [(ngModel)]="user.password"
39
+           [(ngModel)]="user.pwhash"
40 40
            #password="ngModel"
41 41
            name="password"
42 42
            type="password"
@@ -58,14 +58,30 @@
58 58
     <nb-card-body>
59 59
       <nb-checkbox [(ngModel)]="showApplication" name="amMember" #checkbox>I am already a member</nb-checkbox>
60 60
       <br />
61
+      
61 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 73
         </nb-select>
66 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 85
         <textarea nbInput fullWidth placeholder="reason" style="min-height: 400px"></textarea>
70 86
 
71 87
       </span>
@@ -79,7 +95,7 @@
79 95
           size="giant"
80 96
           [disabled]="submitted || !form.valid"
81 97
           [class.btn-pulse]="submitted">
82
-    Log In
98
+    Register
83 99
   </button>
84 100
 </form>
85 101
 

+ 44
- 7
src/frontend/src/app/frontcraft/auth/register/register.component.ts 查看文件

@@ -1,7 +1,9 @@
1 1
 import { Component, OnInit } from '@angular/core';
2
-import { LoginApiService } from '../../services/login-api';
2
+import { LoginApiService, hash } from '../../services/login-api';
3 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 8
 @Component({
7 9
   selector: 'register',
@@ -9,9 +11,22 @@ import { _Rank } from '../../../../../../backend/Types/Types'
9 11
 })
10 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 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 31
   constructor(
17 32
     private router : Router,  
@@ -23,10 +38,32 @@ export class RegisterComponent implements OnInit{
23 38
       if(loggedin){
24 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 查看文件

@@ -65,11 +65,8 @@ export class LoginApiService{
65 65
     getCurrentUser = () : User | undefined => this.auth?this.auth.user:undefined
66 66
 
67 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 71
         if(!auth){ 
75 72
             await this.logout()
@@ -129,6 +126,12 @@ function buf2hex(buffer) { // buffer is an ArrayBuffer
129 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 135
 //angular depenency manager requires this
133 136
 export function initializeLoginSvc(svc: LoginApiService): () => Promise<any> {
134 137
     return svc.initialize

+ 2
- 2
src/frontend/tsconfig.json 查看文件

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

+ 4
- 3
tsconfig.json 查看文件

@@ -7,8 +7,9 @@
7 7
       "declaration": true,
8 8
       "outDir": "./lib",
9 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
 }

正在加载...
取消
保存