Browse Source

rework login and make register

master
peter 5 years ago
parent
commit
030908376b
39 changed files with 687 additions and 418 deletions
  1. 3
    3
      package-lock.json
  2. 1
    1
      package.json
  3. 2
    1
      src/backend/Admin/Admin.ts
  4. 3
    5
      src/backend/Components/Eventbus.ts
  5. 1
    1
      src/backend/Components/Guild/GuildManager.ts
  6. 2
    2
      src/backend/Components/Item/ItemManager.ts
  7. 6
    6
      src/backend/Components/PluginLoader.ts
  8. 6
    6
      src/backend/Components/RPCConfigLoader.ts
  9. 6
    6
      src/backend/Components/Raid/RaidManager.ts
  10. 291
    0
      src/backend/Components/User/LoginManager.ts
  11. 7
    5
      src/backend/Components/User/RPCInterface.ts
  12. 0
    227
      src/backend/Components/User/UserManager.ts
  13. 3
    3
      src/backend/Launcher.ts
  14. 7
    8
      src/backend/Types/Types.ts
  15. 6
    6
      src/frontend/package-lock.json
  16. 1
    1
      src/frontend/package.json
  17. 2
    2
      src/frontend/src/app/@theme/components/footer/footer.component.ts
  18. 1
    4
      src/frontend/src/app/@theme/components/header/header.component.html
  19. 7
    3
      src/frontend/src/app/@theme/components/header/header.component.ts
  20. 1
    0
      src/frontend/src/app/@theme/layouts/index.ts
  21. 9
    0
      src/frontend/src/app/@theme/layouts/one-column-no-sidebar/one-column.layout.scss
  22. 19
    0
      src/frontend/src/app/@theme/layouts/one-column-no-sidebar/one-column.layout.ts
  23. 2
    0
      src/frontend/src/app/@theme/theme.module.ts
  24. 0
    5
      src/frontend/src/app/app-routing.module.ts
  25. 4
    2
      src/frontend/src/app/app.module.ts
  26. 1
    2
      src/frontend/src/app/demo_pages/pages-menu.ts
  27. 1
    0
      src/frontend/src/app/demo_pages/pages-routing.module.ts
  28. 15
    6
      src/frontend/src/app/frontcraft/auth/auth-layout.component.ts
  29. 10
    0
      src/frontend/src/app/frontcraft/auth/auth-routing.module.ts
  30. 9
    2
      src/frontend/src/app/frontcraft/auth/auth.module.ts
  31. 9
    44
      src/frontend/src/app/frontcraft/auth/login/login.component.html
  32. 8
    1
      src/frontend/src/app/frontcraft/auth/login/login.component.ts
  33. 1
    0
      src/frontend/src/app/frontcraft/auth/logout/logout.component.html
  34. 19
    0
      src/frontend/src/app/frontcraft/auth/logout/logout.component.ts
  35. 89
    0
      src/frontend/src/app/frontcraft/auth/register/register.component.html
  36. 32
    0
      src/frontend/src/app/frontcraft/auth/register/register.component.ts
  37. 25
    10
      src/frontend/src/app/frontcraft/pages/pages-layout.component.ts
  38. 4
    2
      src/frontend/src/app/frontcraft/pages/pages.module.ts
  39. 74
    54
      src/frontend/src/app/frontcraft/services/login-api.ts

+ 3
- 3
package-lock.json View File

4961
       }
4961
       }
4962
     },
4962
     },
4963
     "rpclibrary": {
4963
     "rpclibrary": {
4964
-      "version": "1.4.1",
4965
-      "resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.4.1.tgz",
4966
-      "integrity": "sha512-Tv9zOBVT8JFMZfTJgmnX9vvUvtALCDtj/cnlYw2SxsFnj1MuH9VgPniSfThUgdwZZknjFuYVfhLaYb9Yl+eRxQ==",
4964
+      "version": "1.5.2",
4965
+      "resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.5.2.tgz",
4966
+      "integrity": "sha512-BI08DxIcndBf25Rd1k957cTfxhNO9Mr1Y3YBSEuYG2dzI5x2/+T83N3swTn68esjLlzvbcmqMHncd5sCsVmN8w==",
4967
       "requires": {
4967
       "requires": {
4968
         "bsock": "^0.1.9",
4968
         "bsock": "^0.1.9",
4969
         "http": "0.0.0",
4969
         "http": "0.0.0",

+ 1
- 1
package.json View File

37
     "node-fetch": "^2.6.0",
37
     "node-fetch": "^2.6.0",
38
     "path": "^0.12.7",
38
     "path": "^0.12.7",
39
     "rimraf": "^3.0.0",
39
     "rimraf": "^3.0.0",
40
-    "rpclibrary": "^1.4.1",
40
+    "rpclibrary": "^1.5.2",
41
     "simple-git": "^1.124.0",
41
     "simple-git": "^1.124.0",
42
     "spawn-sync": "^2.0.0",
42
     "spawn-sync": "^2.0.0",
43
     "sqlite3": "^4.1.0",
43
     "sqlite3": "^4.1.0",

+ 2
- 1
src/backend/Admin/Admin.ts View File

18
 implements TableDefinitionExporter {
18
 implements TableDefinitionExporter {
19
     knex:Knex
19
     knex:Knex
20
     config: RPCConfigLoader<AdminConf>
20
     config: RPCConfigLoader<AdminConf>
21
+    rpcServer: RPCServer
21
 
22
 
22
     private express
23
     private express
23
     private httpServer
24
     private httpServer
75
     }
76
     }
76
 
77
 
77
     private startWebsocket(){
78
     private startWebsocket(){
78
-        new RPCServer(20000, [
79
+        this.rpcServer = new RPCServer(20000, [
79
             ...this.components,
80
             ...this.components,
80
         ])
81
         ])
81
     }
82
     }

+ 3
- 5
src/backend/Components/Eventbus.ts View File

73
     exportRPCs(){
73
     exportRPCs(){
74
         return [{
74
         return [{
75
             name: 'getNotificationLog' as 'getNotificationLog',
75
             name: 'getNotificationLog' as 'getNotificationLog',
76
-            call: async () => await this.getNotificationLog()
76
+            call: this.getNotificationLog
77
         },{
77
         },{
78
             name: 'pushNotification' as 'pushNotification',
78
             name: 'pushNotification' as 'pushNotification',
79
-            call: async (notification: Notification) => { return await this.pushNotification(notification) }
79
+            call: this.pushNotification
80
         },{
80
         },{
81
             name: 'subscribeNotificaitons' as 'subscribeNotifications',
81
             name: 'subscribeNotificaitons' as 'subscribeNotifications',
82
-            hook: async (callback: Function) => {
83
-                return await this.subscribeNotifications(callback)
84
-            }
82
+            hook: async (callback: Function) =>  await this.subscribeNotifications(callback)
85
         }]
83
         }]
86
     }
84
     }
87
 
85
 

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

33
 
33
 
34
     exportRPCs = () => [{
34
     exportRPCs = () => [{
35
         name: 'getHeadCount' as 'getHeadCount',
35
         name: 'getHeadCount' as 'getHeadCount',
36
-        call: async () => await this.headCount()
36
+        call: this.headCount
37
     },{
37
     },{
38
         name: 'getGuildInfo' as 'getGuildInfo',
38
         name: 'getGuildInfo' as 'getGuildInfo',
39
         call: async () => this.guild.getConfig()
39
         call: async () => this.guild.getConfig()

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

29
     exportRPCs(): RPC<any, any>[]{
29
     exportRPCs(): RPC<any, any>[]{
30
         return [{
30
         return [{
31
             name: 'getItems',
31
             name: 'getItems',
32
-            call: async () => await this.getItems()
32
+            call: this.getItems
33
         },{
33
         },{
34
             name: 'getItem',
34
             name: 'getItem',
35
-            call: async (name:string) => await this.getItem(name) 
35
+            call: this.getItem
36
         }]
36
         }]
37
     }
37
     }
38
 
38
 

+ 6
- 6
src/backend/Components/PluginLoader.ts View File

146
     exportRPCs(){
146
     exportRPCs(){
147
         return [{
147
         return [{
148
             name: "installPlugin" as "installPlugin",
148
             name: "installPlugin" as "installPlugin",
149
-            call: async (name:string, force = false) => {return await this.installPlugin(name, force)},
149
+            call: this.installPlugin,
150
         },{
150
         },{
151
             name: "startPlugin" as "startPlugin",
151
             name: "startPlugin" as "startPlugin",
152
-            call: async (name:string) => {return await this.startPlugin(name)},
152
+            call: this.startPlugin,
153
         },{
153
         },{
154
             name: "updatePlugin" as "updatePlugin",
154
             name: "updatePlugin" as "updatePlugin",
155
-            call: async (name:string) => {return await this.updatePlugin(name)},
155
+            call: this.updatePlugin,
156
         },{
156
         },{
157
             name: "setPluginVersion" as "setPluginVersion",
157
             name: "setPluginVersion" as "setPluginVersion",
158
-            call: async (name:string, tag:string) => {return await this.setPluginVersion(name, tag)},
158
+            call: this.setPluginVersion,
159
         },{
159
         },{
160
             name: "getLoadedPluginNames" as "getLoadedPluginNames",
160
             name: "getLoadedPluginNames" as "getLoadedPluginNames",
161
-            call: async () => {return this.getPlugins().map(p => p.name)},
161
+            call: async () => this.getPlugins().map(p => p.name),
162
         },{
162
         },{
163
             name: "selfUpdate" as "selfUpdate",
163
             name: "selfUpdate" as "selfUpdate",
164
-            call: async (force: boolean) => {return await this.selfUpdate(force)},
164
+            call: this.selfUpdate,
165
         }]
165
         }]
166
     }
166
     }
167
 }
167
 }

+ 6
- 6
src/backend/Components/RPCConfigLoader.ts View File

21
     exportRPCs() {
21
     exportRPCs() {
22
         return [{
22
         return [{
23
             name: "getConfig" as "getConfig",
23
             name: "getConfig" as "getConfig",
24
-            call: () => { return this.getConfig() }
24
+            call: this.getConfig
25
         },{
25
         },{
26
             name: "resetConfig" as "resetConfig",
26
             name: "resetConfig" as "resetConfig",
27
-            call: () => { return this.resetConfig() }
27
+            call: this.resetConfig
28
         },{
28
         },{
29
             name: "setConfig" as "setConfig",
29
             name: "setConfig" as "setConfig",
30
-            call: (conf:ConfT) => { return this.setConfig(conf) }
30
+            call: this.setConfig
31
         },{
31
         },{
32
             name: "setConfigKey" as "setConfigKey",
32
             name: "setConfigKey" as "setConfigKey",
33
-            call: (key:string, value:any) => { return this.setConfigKey(key, value) }
33
+            call: this.setConfigKey
34
         },{
34
         },{
35
             name: "deleteConfigKey" as "deleteConfigKey",
35
             name: "deleteConfigKey" as "deleteConfigKey",
36
-            call: (key:string) => { return this.deleteConfigKey(key) }
36
+            call: this.deleteConfigKey
37
         },{
37
         },{
38
             name: "getConfigKey" as "getConfigKey",
38
             name: "getConfigKey" as "getConfigKey",
39
-            call: (key:string) => { return this.getConfigKey(key) }
39
+            call: this.getConfigKey
40
         }]
40
         }]
41
     }
41
     }
42
 }
42
 }

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

15
             name: 'manageRaid' as 'manageRaid',
15
             name: 'manageRaid' as 'manageRaid',
16
             exportRPCs: () => [{
16
             exportRPCs: () => [{
17
                 name: 'createRaid' as 'createRaid',
17
                 name: 'createRaid' as 'createRaid',
18
-                call: async (raid:Raid) => await this.createRaid(raid)
18
+                call: this.createRaid
19
             },{
19
             },{
20
                 name: 'addSignup' as 'addSignup',
20
                 name: 'addSignup' as 'addSignup',
21
-                call: async(signup: Signup) => await this.addSignup(signup)
21
+                call: this.addSignup
22
             },{
22
             },{
23
                 name: 'removeSignup' as 'removeSignup',
23
                 name: 'removeSignup' as 'removeSignup',
24
-                call: async(signup: Signup) => await this.removeSignup(signup)
24
+                call: this.removeSignup
25
             }]
25
             }]
26
         },{
26
         },{
27
             name: 'signup' as 'signup',
27
             name: 'signup' as 'signup',
28
             exportRPCs: () => [{
28
             exportRPCs: () => [{
29
                 name: 'getRaids' as 'getRaids',
29
                 name: 'getRaids' as 'getRaids',
30
-                call: async () => await this.getRaids()
30
+                call: this.getRaids
31
             },{
31
             },{
32
                 name: 'getSingups' as 'getSingups',
32
                 name: 'getSingups' as 'getSingups',
33
-                call: async(raid: Raid) => await this.getSignups(raid)
33
+                call: this.getSignups
34
             },{
34
             },{
35
                 name: 'sign' as 'sign',
35
                 name: 'sign' as 'sign',
36
-                call: async(user:User, raid:Raid) => await this.sign(user, raid)
36
+                call: this.sign
37
             }]
37
             }]
38
         },]
38
         },]
39
     }
39
     }

+ 291
- 0
src/backend/Components/User/LoginManager.ts View File

1
+import { RPCServer, Socket } from "rpclibrary";
2
+import { TableDefiniton, AnyRPCExporter, User, RPCPermission, Token, Auth, Rank, FrontcraftFeatureIfc, _Rank } from "../../Types/Types";
3
+import { FrontworkAdmin } from "../../Admin/Admin";
4
+import { PrivilegedRPCExporter } from "../../Types/PrivilegedRPCExporter";
5
+import { FrontworkComponent } from "../../Types/FrontworkComponent";
6
+import { getSpecTableData } from "../../Types/PlayerSpecs"
7
+import { LoginManagerIfc, LoginManagerFeatureIfc } from "./RPCInterface";
8
+const uuid = require('uuid/v4')
9
+
10
+const ONE_WEEK = 604800000 
11
+
12
+type Serverstate = {
13
+    server: RPCServer,
14
+    port : number,
15
+    allowed: string[]
16
+}
17
+
18
+export class LoginManager
19
+implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>{
20
+    name = "Authenticator" as "Authenticator";   
21
+    admin:FrontworkAdmin
22
+    
23
+    rankServers : {[rank in Rank] : Serverstate}
24
+    userLogins : {[username in string] : {
25
+        connections: {[port in number]: Socket}
26
+        auth: Auth
27
+    }} = {}
28
+
29
+    constructor(
30
+        private exporters: PrivilegedRPCExporter[]
31
+    ){}
32
+
33
+    exportRPCs = () => [
34
+        {
35
+            name: 'login' as 'login',
36
+            call: this.login 
37
+        },{
38
+            name: 'logout' as 'logout',
39
+            call: this.logout
40
+        },{
41
+            name: 'getAuth' as 'getAuth',
42
+            call: this.getAuth
43
+        },{
44
+            name: 'checkToken' as 'checkToken',
45
+            call: async (tokenValue : string, rank: Rank) => this.checkToken(tokenValue, rank)
46
+        }
47
+    ]
48
+
49
+    onSetAdmin(admin:FrontworkAdmin){
50
+        this.exporters.forEach(e => e['admin'] = admin)
51
+    }
52
+
53
+    exportRPCFeatures = () => [
54
+        {
55
+            name: 'createUser' as 'createUser',
56
+            exportRPCs: () => [{
57
+                name: 'createUser' as 'createUser',
58
+                call: this.createUser
59
+            }]
60
+        },{
61
+            name: 'modifyPermissions' as 'modifyPermissions',
62
+            exportRPCs: () => [{
63
+                name: 'getPermissions' as 'getPermissions',
64
+                call: this.getPermissions 
65
+            },{
66
+                name: 'setPermission' as 'setPermission',
67
+                call: this.setPermission
68
+            }]
69
+        }
70
+    ]
71
+    
72
+    
73
+    getTableDefinitions = (): TableDefiniton[] => [
74
+        {
75
+            name: 'users',
76
+            tableBuilder: (table) => {
77
+                table.increments("id").primary()
78
+                table.string("name").notNullable().unique()
79
+                table.string("pwhash").notNullable()
80
+                table.string("rank").notNullable()
81
+                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")
92
+            }
93
+        },{
94
+            name: 'rpcpermissions',
95
+            tableBuilder: (table) => {
96
+                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')
106
+            }
107
+        }
108
+        ,...this.exporters.flatMap(exp => exp['getTableDefinitions']?exp['getTableDefinitions']():undefined)
109
+    ]
110
+
111
+    initialize = async () => {
112
+        //set up permissions
113
+        await Promise.all( 
114
+            [this, ...this.exporters].flatMap(exp => exp.exportRPCFeatures().map(async (feature) => {
115
+            try{
116
+                await this.admin.knex.insert({ name: feature.name }).into('rpcpermissions')
117
+            }catch(e){}
118
+        })))
119
+
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
127
+        const rankServers : any = {}   
128
+
129
+        for(let i = 0; i < _Rank.length; i++){
130
+            const rank:Rank = _Rank[i]
131
+            const port = 20001 + i
132
+            const rankServer = await this.startRankServer(rank, port)
133
+            rankServers[rank] = {
134
+                server: rankServer,
135
+                port: port,
136
+                allowed: []
137
+            }
138
+        }
139
+        this.rankServers = rankServers
140
+    
141
+        setInterval(this.checkExpiredSessions, 600_000)        
142
+    }
143
+
144
+    checkExpiredSessions = () => {
145
+        Object.values(this.userLogins).map(userLogin => {
146
+            const auth = userLogin.auth
147
+            if(!this.checkToken(auth.token.value, auth.user.rank)){
148
+                this.logout(auth.user.name, auth.token.value)
149
+            }
150
+        })
151
+    }
152
+
153
+    checkConnection = async (socket: Socket) => {
154
+        let data : Auth | false = false
155
+        while(!data){
156
+            data = await Promise.race([socket.call('getUserData'), new Promise((res, rej) => { setTimeout(res, 250);})])
157
+        } 
158
+        this.userLogins[data.user.name].connections[socket.port] = socket
159
+        await socket.call('navigate', ["/frontcraft/dashboard"])
160
+        return true
161
+    }
162
+
163
+    setPermission = async (permission: RPCPermission) => {
164
+        await this.admin.knex('rpcpermissions')
165
+        .where('rpcname', '=', permission.name)
166
+        .update(permission)
167
+    }
168
+
169
+    getPermissions = async () : Promise<RPCPermission[]> => {
170
+        return await this.admin.knex.select('*').from('rpcpermissions')
171
+    }
172
+
173
+    getPermission = async (feature: keyof FrontcraftFeatureIfc, rank:Rank) : Promise<boolean> => {
174
+        const perm : RPCPermission[] = await this.admin.knex
175
+            .select(rank)
176
+            .from('rpcpermissions')
177
+            .where('name', '=', <string>feature)
178
+
179
+        if(perm.length === 0) return false
180
+        return perm[0][rank]
181
+    }
182
+
183
+    getRPCForRank = async (rank: Rank): Promise<AnyRPCExporter[]> => {
184
+        return [
185
+            ...this.exportRPCFeatures(), 
186
+            ...this.exporters.flatMap((exp) => exp.exportRPCFeatures())
187
+        ].filter(async (feature) => await this.getPermission(<keyof FrontcraftFeatureIfc> feature.name, rank))
188
+    }
189
+
190
+    createUser = async(user:User): Promise<User> => {
191
+        await this.admin.knex('users')
192
+        .insert(user)
193
+        
194
+        const users = await this.admin.knex
195
+        .select("*")
196
+        .from('users')
197
+        .where(user)
198
+        return users[0]
199
+    }
200
+
201
+    logout = async (username:string, tokenValue : string) : Promise<void> => {
202
+        try{
203
+
204
+            await Promise.all (Object.values(this.userLogins[username].connections).map(async (sock) => {
205
+                await sock.call('navigate', '/auth/login')
206
+            }))
207
+
208
+            Object.values(this.rankServers)
209
+                .forEach(state => {
210
+                    state.allowed = state.allowed.filter(allowed => allowed !== tokenValue)
211
+            })
212
+
213
+            delete this.userLogins[username]
214
+        }catch(e){
215
+            console.log(e)
216
+        }
217
+    }
218
+
219
+    login = async(username:string, pwHash:string) : Promise<Auth> => {
220
+        const res:User[] = await this.admin.knex
221
+        .select('*')
222
+        .from('users')
223
+        .where({ name: username })
224
+
225
+        if(res.length > 0 && pwHash === res[0].pwhash){
226
+            const user:User = res[0]
227
+            delete user.pwhash
228
+
229
+            //return existing auth
230
+            if(this.userLogins[username] != null){
231
+                return this.userLogins[username].auth
232
+            }
233
+            
234
+            const token = this.createToken(user)
235
+            const userAuth : Auth = {
236
+                token: token,
237
+                user: user,
238
+                port: this.rankServers[user.rank].port
239
+            }
240
+
241
+            this.userLogins[user.name] = {connections: {}, auth: userAuth}
242
+            this.rankServers[user.rank].allowed.push(token.value)
243
+
244
+            return userAuth 
245
+        }
246
+
247
+        throw new Error('login failed')
248
+    }
249
+
250
+    getAuth = async (tokenValue:string) : Promise<Auth> => {
251
+        const maybeAuth = Object.values(this.userLogins).find(login => login.auth.token.value === tokenValue)
252
+        if(maybeAuth)
253
+            return maybeAuth.auth
254
+
255
+        throw new Error("Bad token")
256
+    }
257
+
258
+    startRankServer = async (rank : Rank, port: number) : Promise<RPCServer> => {
259
+        const allowedRPCs = await this.getRPCForRank(rank)
260
+        let rpcServer : RPCServer = new RPCServer(port, allowedRPCs, {
261
+            closeHandler: (socket) => { 
262
+                Object.values(this.userLogins)
263
+                    .forEach(login => delete login.connections[socket.port])
264
+
265
+            },
266
+            connectionHandler: (socket) => {
267
+                this.checkConnection(socket).catch(() => {}) //sometimes times out if you go too fast
268
+            },
269
+            sesame: (sesame) => this.checkToken(sesame, rank)
270
+        })
271
+        return rpcServer
272
+    }
273
+
274
+    checkToken = (token: string, rank: Rank) : boolean => this.rankServers[rank].allowed.includes(token)
275
+                                                       && Object.values(this.userLogins).find(login => login.auth.token.value === token)!.auth.token.created > Date.now() - ONE_WEEK
276
+
277
+    createToken = (user:User): Token => {
278
+        
279
+        if(this.userLogins[user.name]){
280
+            return this.userLogins[user.name].auth.token
281
+        }
282
+
283
+        const token:Token = {
284
+            value: uuid(),
285
+            user_id: user.id!,
286
+            created: Date.now()
287
+        }
288
+
289
+        return token
290
+    }
291
+}

+ 7
- 5
src/backend/Components/User/RPCInterface.ts View File

1
-import { Token, Auth, User, RPCPermission } from "../../Types/Types"
1
+import { Token, Auth, User, RPCPermission, Rank } from "../../Types/Types"
2
 
2
 
3
-export type UserManagerIfc = {
3
+export type LoginManagerIfc = {
4
     Authenticator: {
4
     Authenticator: {
5
-        login: (username:string, pwHash:string) => Promise<Token>
6
-        authenticate: (token:string | Token) => Promise<Auth>
5
+        login: (username:string, pwHash:string) => Promise<Auth>
6
+        logout: (username: string, tokenValue :string) => Promise<void>
7
+        getAuth: (tokenValue: string) => Promise<Auth>
8
+        checkToken: (token: string, rank: Rank) => Promise<boolean>
7
     }
9
     }
8
 }
10
 }
9
 
11
 
10
-export type UserManagerFeatureIfc = {
12
+export type LoginManagerFeatureIfc = {
11
     createUser: {
13
     createUser: {
12
         createUser: (user:User) => Promise<User>
14
         createUser: (user:User) => Promise<User>
13
     }
15
     }

+ 0
- 227
src/backend/Components/User/UserManager.ts View File

1
-import { RPCServer } from "rpclibrary";
2
-import { TableDefiniton, AnyRPCExporter, User, RPCPermission, _Rank, Token, Auth, Rank, FrontcraftFeatureIfc } from "../../Types/Types";
3
-import { FrontworkAdmin } from "../../Admin/Admin";
4
-import { PrivilegedRPCExporter } from "../../Types/PrivilegedRPCExporter";
5
-import { FrontworkComponent } from "../../Types/FrontworkComponent";
6
-import { getSpecTableData } from "../../Types/PlayerSpecs"
7
-import { UserManagerIfc, UserManagerFeatureIfc } from "./RPCInterface";
8
-const uuid = require('uuid/v4')
9
-
10
-export class LoginManager
11
-implements FrontworkComponent<UserManagerIfc, UserManagerFeatureIfc>{
12
-    name = "Authenticator" as "Authenticator";   
13
-    admin:FrontworkAdmin
14
-    
15
-    constructor(
16
-        private exporters: PrivilegedRPCExporter[]
17
-    ){}
18
-
19
-    exportRPCs = () => [
20
-        {
21
-            name: 'login' as 'login',
22
-            call: async (username:string, pwHash:string) => await this.login(username, pwHash) 
23
-        },{
24
-            name: 'authenticate' as 'authenticate',
25
-            call: async (tokenValue:string | Token) => await this.authenticate(tokenValue)
26
-        }
27
-    ]
28
-
29
-    onSetAdmin(admin:FrontworkAdmin){
30
-        this.exporters.forEach(e => e['admin'] = admin)
31
-    }
32
-
33
-    exportRPCFeatures = () => [
34
-        {
35
-            name: 'createUser' as 'createUser',
36
-            exportRPCs: () => [{
37
-                name: 'createUser' as 'createUser',
38
-                call: async (user:User) => await this.createUser(user)
39
-            }]
40
-        },{
41
-            name: 'modifyPermissions' as 'modifyPermissions',
42
-            exportRPCs: () => [{
43
-                name: 'getPermissions' as 'getPermissions',
44
-                call: async () => await this.getPermissions() 
45
-            },{
46
-                name: 'setPermission' as 'setPermission',
47
-                call: async (perm: RPCPermission) => await this.setPermission(perm) 
48
-            }]
49
-        }
50
-    ]
51
-    
52
-    
53
-    getTableDefinitions = (): TableDefiniton[] => [
54
-        {
55
-            name: 'users',
56
-            tableBuilder: (table) => {
57
-                table.increments("id").primary()
58
-                table.string("name").notNullable().unique()
59
-                table.string("pwhash").notNullable()
60
-                table.string("rank").notNullable()
61
-                table.string("email").nullable().unique()
62
-            }
63
-        },{
64
-            name: 'characters',
65
-            tableBuilder: (table) => {
66
-                table.increments("id").primary()
67
-                table.string("name").notNullable().unique()
68
-                table.integer("specid").notNullable()
69
-                table.foreign("specid").references("specs.id")
70
-                table.integer("userid").notNullable()
71
-                table.foreign("userid").references("users.id")
72
-            }
73
-        },{
74
-            name: 'rpcpermissions',
75
-            tableBuilder: (table) => {
76
-                table.string("name").primary().notNullable()
77
-                table.boolean("ADMIN").defaultTo(true).notNullable()
78
-                _Rank.forEach(r => table.boolean(r).defaultTo(false).notNullable())
79
-            }
80
-        },{
81
-            name: 'tokens',
82
-            tableBuilder: (table) => {
83
-                table.string('value').primary()
84
-                table.integer('user_id').notNullable()
85
-                table.foreign('user_id').references('users')
86
-                table.dateTime('created').defaultTo(this.admin.knex.fn.now())
87
-            }
88
-        },{
89
-            name: 'specs',
90
-            tableBuilder: (table) => {
91
-                table.string('class')
92
-                table.string('name')
93
-                table.primary(['class', 'name'])
94
-            }
95
-        }
96
-        ,...this.exporters.flatMap(exp => exp['getTableDefinitions']?exp['getTableDefinitions']():undefined)
97
-    ]
98
-    
99
-
100
-    async initialize(){
101
-        await Promise.all( 
102
-            [this, ...this.exporters].flatMap(exp => exp.exportRPCFeatures().map(async (feature) => {
103
-            try{
104
-                await this.admin.knex.insert({ name: feature.name }).into('rpcpermissions')
105
-            }catch(e){}
106
-        })))
107
-
108
-        await Promise.all(this.exporters.map(ex => ex['initialize']?ex['initialize']():undefined))
109
-
110
-        await this.admin.knex('specs').insert(getSpecTableData()).catch(e => { console.log("skipping spec insertion") })
111
-    }
112
-
113
-    async setPermission(permission: RPCPermission){
114
-        await this.admin.knex('rpcpermissions')
115
-        .where('rpcname', '=', permission.name)
116
-        .update(permission)
117
-    }
118
-
119
-    getPermissions = async () : Promise<RPCPermission[]> => {
120
-        return await this.admin.knex.select('*').from('rpcpermissions')
121
-    }
122
-
123
-    getPermission = async (feature: keyof FrontcraftFeatureIfc, rank:Rank) : Promise<boolean> => {
124
-        const perm : RPCPermission[] = await this.admin.knex
125
-            .select(rank)
126
-            .from('rpcpermissions')
127
-            .where('name', '=', <string>feature)
128
-
129
-        if(perm.length === 0) return false
130
-        return perm[0][rank]
131
-    }
132
-
133
-    getRPCForUser = async (user:User): Promise<AnyRPCExporter[]> => {
134
-        return [
135
-            ...this.exportRPCFeatures(), 
136
-            ...this.exporters.flatMap((exp) => exp.exportRPCFeatures())
137
-        ].filter(async (feature) => await this.getPermission(<keyof FrontcraftFeatureIfc> feature.name, user.rank))
138
-    }
139
-
140
-    createUser = async(user:User): Promise<User> => {
141
-        await this.admin.knex('users')
142
-        .insert(user)
143
-        
144
-        const users = await this.admin.knex
145
-        .select("*")
146
-        .from('users')
147
-        .where(user)
148
-        return users[0]
149
-    }
150
-
151
-    login = async(username:string, pwHash:string) : Promise<Token> => {
152
-        const res:User[] = await this.admin.knex
153
-        .select("*")
154
-        .from('users')
155
-        .where({ name: username })
156
-        
157
-        if(res.length > 0 && pwHash === res[0].pwhash){
158
-            return await this.createToken(res[0])
159
-        }
160
-
161
-        throw new Error('login failed')
162
-    }
163
-
164
-    authenticate = async(tokenValue: string | Token) : Promise<Auth> => {
165
-        if(typeof tokenValue !== 'string') tokenValue = tokenValue.value 
166
-
167
-        const res : User[] = await this.admin.knex
168
-            .select('users.id', 'name', 'specid', 'rank', 'email')
169
-            .from('tokens')
170
-            .join('users', function(){
171
-                this.on('users.id', '=', 'tokens.user_id')
172
-            })
173
-            .where({ value: tokenValue})
174
-
175
-        if(res.length === 0)
176
-            throw new Error('authentication failed')
177
-
178
-        const allowedRPCs = await this.getRPCForUser(res[0])
179
-        const randomPort = 20000 + Math.floor(Math.random() * 10000)
180
-        while(true){
181
-            try{
182
-                let commSock = new RPCServer(randomPort, allowedRPCs, {
183
-                    closeHandler: () => { 
184
-                        console.log(res[0].name, 'disconnected')
185
-                        commSock.destroy() 
186
-                    },
187
-                    connectionHandler: () => {
188
-                        console.log(res[0].name, 'connected')
189
-                        cancelTimeout()
190
-                    },
191
-                    sesame: tokenValue
192
-                })
193
-                const timeout = setTimeout(() => {
194
-                    console.log(res[0].name, 'timeout')
195
-                    commSock.destroy()
196
-                }, 10000)
197
-                const cancelTimeout = () => { clearTimeout(timeout) }
198
-                break;
199
-            }catch(e){
200
-                //retry
201
-            }
202
-        }
203
-
204
-        return {
205
-            port: randomPort,
206
-            user: res[0],
207
-            token: {
208
-                value: tokenValue,
209
-                user_id: res[0].id!
210
-            }
211
-        }
212
-    }
213
-
214
-    createToken = async(user:User): Promise<Token> => {
215
-        const old = await this.admin.knex.select('*').from('tokens').where({user_id: user.id})
216
-        if(old.length === 0){
217
-            const token:Token = {
218
-                value: uuid(),
219
-                user_id: user.id!
220
-            }
221
-            await this.admin.knex('tokens').insert(token)
222
-            return token
223
-        }else{
224
-            return old[0]
225
-        }
226
-    }
227
-}

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

1
 import { FrontworkAdmin } from './Admin/Admin'
1
 import { FrontworkAdmin } from './Admin/Admin'
2
 import { RaidManager } from "./Components/Raid/RaidManager";
2
 import { RaidManager } from "./Components/Raid/RaidManager";
3
 import { ItemManager } from "./Components/Item/ItemManager";
3
 import { ItemManager } from "./Components/Item/ItemManager";
4
-import { LoginManager } from "./Components/User/UserManager";
4
+import { LoginManager } from "./Components/User/LoginManager";
5
 import { Debugger } from './Components/Debugger/Debugger';
5
 import { Debugger } from './Components/Debugger/Debugger';
6
 import { FrontworkComponent } from './Types/FrontworkComponent';
6
 import { FrontworkComponent } from './Types/FrontworkComponent';
7
 import { GuildManager } from './Components/Guild/GuildManager';
7
 import { GuildManager } from './Components/Guild/GuildManager';
10
 let raidManager = new RaidManager()
10
 let raidManager = new RaidManager()
11
 let itemManager = new ItemManager()
11
 let itemManager = new ItemManager()
12
 let guildManager = new GuildManager()
12
 let guildManager = new GuildManager()
13
-let userManager = new LoginManager([
13
+let loginManager = new LoginManager([
14
     raidManager,
14
     raidManager,
15
     itemManager,
15
     itemManager,
16
     guildManager
16
     guildManager
17
 ])
17
 ])
18
 
18
 
19
-let components:FrontworkComponent[] = [ guildManager, raidManager, itemManager, userManager ]
19
+let components:FrontworkComponent[] = [ guildManager, raidManager, itemManager, loginManager ]
20
 let dbg = new Debugger(components)
20
 let dbg = new Debugger(components)
21
 
21
 
22
 
22
 

+ 7
- 8
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";
3
 import { RaidManagerFeatureIfc } from "../Components/Raid/RPCInterface";
4
-import { ItemManagerIfc, ItemManagerFeatureIfc } from "../Components/Item/RPCInterface";
5
-import { UserManagerIfc, UserManagerFeatureIfc } from "../Components/User/RPCInterface";
4
+import { LoginManagerIfc, LoginManagerFeatureIfc } from "../Components/User/RPCInterface";
6
 
5
 
7
 
6
 
8
 export declare type NotificationSeverity = 'Info' | 'Important' | 'Error';
7
 export declare type NotificationSeverity = 'Info' | 'Important' | 'Error';
19
 }
18
 }
20
 
19
 
21
 export type Rank =             "ADMIN" | "Guildmaster" | "Officer" | "Classleader" | "Raider" | "Trial" | "Social" | "Guest"
20
 export type Rank =             "ADMIN" | "Guildmaster" | "Officer" | "Classleader" | "Raider" | "Trial" | "Social" | "Guest"
22
-export const _Rank : Rank[] = ["Guildmaster" , "Officer" , "Classleader" , "Raider" , "Trial" , "Social" , "Guest"]
21
+export const _Rank : Rank[] = ["ADMIN" , "Guildmaster" , "Officer" , "Classleader" , "Raider" , "Trial" , "Social" , "Guest"]
23
 export type Class =              "Warrior" | "Rogue" | "Hunter" | "Mage" | "Warlock" | "Priest" | "Shaman" | "Paladin" | "Druid"
22
 export type Class =              "Warrior" | "Rogue" | "Hunter" | "Mage" | "Warlock" | "Priest" | "Shaman" | "Paladin" | "Druid"
24
 export const _Class : Class[] = ["Warrior" , "Rogue" , "Hunter" , "Mage" , "Warlock" , "Priest" , "Shaman" , "Paladin" , "Druid"]
23
 export const _Class : Class[] = ["Warrior" , "Rogue" , "Hunter" , "Mage" , "Warlock" , "Priest" , "Shaman" , "Paladin" , "Druid"]
25
 
24
 
56
 export type Token = {
55
 export type Token = {
57
     value: string
56
     value: string
58
     user_id: number
57
     user_id: number
59
-    created?: number
58
+    created: number
60
 }
59
 }
61
 
60
 
62
 export type Auth = {port: number, user: User, token: Token}
61
 export type Auth = {port: number, user: User, token: Token}
63
 
62
 
64
-export type FrontcraftIfc = UserManagerIfc 
65
-                          & ItemManagerIfc
63
+export type FrontcraftIfc = LoginManagerIfc 
64
+                          //& ItemManagerIfc
66
 
65
 
67
 export type FrontcraftFeatureIfc = RaidManagerFeatureIfc 
66
 export type FrontcraftFeatureIfc = RaidManagerFeatureIfc 
68
-                                 & UserManagerFeatureIfc
69
-                                 & ItemManagerFeatureIfc
67
+                                 & LoginManagerFeatureIfc
68
+                                 //& ItemManagerFeatureIfc
70
 
69
 
71
 export type Spec = {
70
 export type Spec = {
72
     id?: number,
71
     id?: number,

+ 6
- 6
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.4.2",
14273
-      "resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.4.2.tgz",
14274
-      "integrity": "sha512-IFigD+65a9MM+1AgEH5nurUzCyMg9hawqtnOA67/PtTGP5GsnWxaFESKl03k8L/PQ8ptZkWcub/63bfxkrwyMw==",
14272
+      "version": "1.5.1",
14273
+      "resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.5.1.tgz",
14274
+      "integrity": "sha512-EN6wlifkFmEQrHhtbalS0i90ZBNbLNFcrQ8hTrcJLBuNMFab49R8i5fruoDLDJM88iPcx6eWccI6zLHK7Qkl2A==",
14275
       "requires": {
14275
       "requires": {
14276
         "bsock": "^0.1.9",
14276
         "bsock": "^0.1.9",
14277
         "http": "0.0.0",
14277
         "http": "0.0.0",
14279
       },
14279
       },
14280
       "dependencies": {
14280
       "dependencies": {
14281
         "uuid": {
14281
         "uuid": {
14282
-          "version": "3.3.3",
14283
-          "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz",
14284
-          "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ=="
14282
+          "version": "3.4.0",
14283
+          "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
14284
+          "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
14285
         }
14285
         }
14286
       }
14286
       }
14287
     },
14287
     },

+ 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.4.2",
72
+    "rpclibrary": "^1.5.1",
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",

+ 2
- 2
src/frontend/src/app/@theme/components/footer/footer.component.ts View File

4
   selector: 'ngx-footer',
4
   selector: 'ngx-footer',
5
   styleUrls: ['./footer.component.scss'],
5
   styleUrls: ['./footer.component.scss'],
6
   template: `
6
   template: `
7
-    <span class="created-by">Created with <i class="fa fa-gamepad"></i> by <b><a href="https://frontcraft.me" target="_blank">FrontCraft</a></b></span>
7
+    <span class="created-by">Created with <i class="fa fa-gamepad"></i> by <b><a href="https://gitea.nitowa.xyz/explore/repos" target="_blank">nitowa.xyz</a></b></span>
8
     <div class="socials">
8
     <div class="socials">
9
-      <a href="http://www.versioncontrol.me/" target="_blank" class="ion ion-social-github"></a>
9
+      <a href="https://gitea.nitowa.xyz/" target="_blank" class="ion ion-social-github"></a>
10
     </div>
10
     </div>
11
   `,
11
   `,
12
 })
12
 })

+ 1
- 4
src/frontend/src/app/@theme/components/header/header.component.html View File

10
 <div class="header-container">
10
 <div class="header-container">
11
   <nb-actions size="small">
11
   <nb-actions size="small">
12
 
12
 
13
-    <nb-action class="control-item">
14
-      <nb-search type="rotate-layout"></nb-search>
15
-    </nb-action>
16
-    <nb-action class="control-item" icon="email-outline"></nb-action>
13
+    <nb-action class="control-item" icon="message-square-outline"></nb-action>
17
     <nb-action class="control-item" icon="bell-outline"></nb-action>
14
     <nb-action class="control-item" icon="bell-outline"></nb-action>
18
 
15
 
19
     <nb-action class="user-action">
16
     <nb-action class="user-action">

+ 7
- 3
src/frontend/src/app/@theme/components/header/header.component.ts View File

1
 import { Component, OnDestroy, OnInit } from '@angular/core';
1
 import { Component, OnDestroy, OnInit } from '@angular/core';
2
-import { NbMediaBreakpointsService, NbMenuService, NbSidebarService, NbThemeService } from '@nebular/theme';
2
+import { NbMediaBreakpointsService, NbMenuService, NbSidebarService, NbThemeService, NbContextMenuComponent, NbMenuItem } from '@nebular/theme';
3
 
3
 
4
 import { LayoutService } from '../../../@core/utils';
4
 import { LayoutService } from '../../../@core/utils';
5
 import { map, takeUntil } from 'rxjs/operators';
5
 import { map, takeUntil } from 'rxjs/operators';
39
 
39
 
40
   currentTheme = 'dark';
40
   currentTheme = 'dark';
41
 
41
 
42
-  userMenu = [ { title: 'Profile' }, { title: 'Log out' } ];
42
+  userMenu : NbMenuItem[] = [ { title: 'Profile' }, { title: 'Log out', url: '/auth/logout' } ];
43
 
43
 
44
   constructor(private sidebarService: NbSidebarService,
44
   constructor(private sidebarService: NbSidebarService,
45
               private menuService: NbMenuService,
45
               private menuService: NbMenuService,
46
               private themeService: NbThemeService,
46
               private themeService: NbThemeService,
47
               private layoutService: LayoutService,
47
               private layoutService: LayoutService,
48
               private breakpointService: NbMediaBreakpointsService,
48
               private breakpointService: NbMediaBreakpointsService,
49
-              private loginService: LoginApiService
49
+              private loginService: LoginApiService,
50
              ) {}
50
              ) {}
51
 
51
 
52
   ngOnInit() {
52
   ngOnInit() {
92
     return false;
92
     return false;
93
   }
93
   }
94
 
94
 
95
+  logout() {
96
+    this.loginService.logout()
97
+  }
98
+
95
   navigateHome() {
99
   navigateHome() {
96
     this.menuService.navigateHome();
100
     this.menuService.navigateHome();
97
     return false;
101
     return false;

+ 1
- 0
src/frontend/src/app/@theme/layouts/index.ts View File

1
 export * from './one-column/one-column.layout';
1
 export * from './one-column/one-column.layout';
2
 export * from './two-columns/two-columns.layout';
2
 export * from './two-columns/two-columns.layout';
3
 export * from './three-columns/three-columns.layout';
3
 export * from './three-columns/three-columns.layout';
4
+export * from './one-column-no-sidebar/one-column.layout';

+ 9
- 0
src/frontend/src/app/@theme/layouts/one-column-no-sidebar/one-column.layout.scss View File

1
+@import '../../styles/themes';
2
+@import '~bootstrap/scss/mixins/breakpoints';
3
+@import '~@nebular/theme/styles/global/breakpoints';
4
+
5
+@include nb-install-component() {
6
+  .menu-sidebar ::ng-deep .scrollable {
7
+    padding-top: nb-theme(layout-padding-top);
8
+  }
9
+}

+ 19
- 0
src/frontend/src/app/@theme/layouts/one-column-no-sidebar/one-column.layout.ts View File

1
+import { Component } from '@angular/core';
2
+
3
+@Component({
4
+  selector: 'ngx-one-column-no-sidebar-layout',
5
+  styleUrls: ['./one-column.layout.scss'],
6
+  template: `
7
+    <nb-layout windowMode>
8
+ 
9
+      <nb-layout-column>
10
+        <ng-content select="router-outlet"></ng-content>
11
+      </nb-layout-column>
12
+
13
+      <nb-layout-footer fixed>
14
+        <ngx-footer></ngx-footer>
15
+      </nb-layout-footer>
16
+    </nb-layout>
17
+  `,
18
+})
19
+export class OneColumnNoSidebarLayoutComponent {}

+ 2
- 0
src/frontend/src/app/@theme/theme.module.ts View File

33
   OneColumnLayoutComponent,
33
   OneColumnLayoutComponent,
34
   ThreeColumnsLayoutComponent,
34
   ThreeColumnsLayoutComponent,
35
   TwoColumnsLayoutComponent,
35
   TwoColumnsLayoutComponent,
36
+  OneColumnNoSidebarLayoutComponent,
36
 } from './layouts';
37
 } from './layouts';
37
 import { DEFAULT_THEME } from './styles/theme.default';
38
 import { DEFAULT_THEME } from './styles/theme.default';
38
 import { COSMIC_THEME } from './styles/theme.cosmic';
39
 import { COSMIC_THEME } from './styles/theme.cosmic';
61
   OneColumnLayoutComponent,
62
   OneColumnLayoutComponent,
62
   ThreeColumnsLayoutComponent,
63
   ThreeColumnsLayoutComponent,
63
   TwoColumnsLayoutComponent,
64
   TwoColumnsLayoutComponent,
65
+  OneColumnNoSidebarLayoutComponent
64
 ];
66
 ];
65
 const PIPES = [
67
 const PIPES = [
66
   CapitalizePipe,
68
   CapitalizePipe,

+ 0
- 5
src/frontend/src/app/app-routing.module.ts View File

2
 import { NgModule } from '@angular/core';
2
 import { NgModule } from '@angular/core';
3
 
3
 
4
 const routes: Routes = [
4
 const routes: Routes = [
5
-  {
6
-    path: 'pages',
7
-    loadChildren: () => import('./demo_pages/pages.module')
8
-      .then(m => m.PagesModule),
9
-  },
10
   {
5
   {
11
     path: 'auth',
6
     path: 'auth',
12
     loadChildren: () => import('./frontcraft/auth/auth.module')
7
     loadChildren: () => import('./frontcraft/auth/auth.module')

+ 4
- 2
src/frontend/src/app/app.module.ts View File

20
   NbToastrModule,
20
   NbToastrModule,
21
   NbWindowModule,
21
   NbWindowModule,
22
 } from '@nebular/theme';
22
 } from '@nebular/theme';
23
+import { LoginApiService } from './frontcraft/services/login-api';
23
 
24
 
24
 @NgModule({
25
 @NgModule({
25
   declarations: [AppComponent],
26
   declarations: [AppComponent],
28
     BrowserAnimationsModule,
29
     BrowserAnimationsModule,
29
     HttpClientModule,
30
     HttpClientModule,
30
     AppRoutingModule,
31
     AppRoutingModule,
31
-
32
     ThemeModule.forRoot(),
32
     ThemeModule.forRoot(),
33
-
34
     NbSidebarModule.forRoot(),
33
     NbSidebarModule.forRoot(),
35
     NbMenuModule.forRoot(),
34
     NbMenuModule.forRoot(),
36
     NbDatepickerModule.forRoot(),
35
     NbDatepickerModule.forRoot(),
43
     CoreModule.forRoot(),
42
     CoreModule.forRoot(),
44
   ],
43
   ],
45
   bootstrap: [AppComponent],
44
   bootstrap: [AppComponent],
45
+  providers: [
46
+    
47
+  ]
46
 })
48
 })
47
 export class AppModule {
49
 export class AppModule {
48
 }
50
 }

+ 1
- 2
src/frontend/src/app/demo_pages/pages-menu.ts View File

1
 import { NbMenuItem } from '@nebular/theme';
1
 import { NbMenuItem } from '@nebular/theme';
2
 
2
 
3
-export const MENU_ITEMS: NbMenuItem[] = [
4
-];
3
+export const MENU_ITEMS: NbMenuItem[] = [];

+ 1
- 0
src/frontend/src/app/demo_pages/pages-routing.module.ts View File

3
 
3
 
4
 import { PagesComponent } from './pages.component';
4
 import { PagesComponent } from './pages.component';
5
 import { NotFoundComponent } from './miscellaneous/not-found/not-found.component';
5
 import { NotFoundComponent } from './miscellaneous/not-found/not-found.component';
6
+import { AuthComponent } from '../frontcraft/auth/auth-layout.component';
6
 
7
 
7
 const routes: Routes = [{
8
 const routes: Routes = [{
8
   path: '',
9
   path: '',

+ 15
- 6
src/frontend/src/app/frontcraft/auth/auth-layout.component.ts View File

1
-import { Component } from '@angular/core';
1
+import { Component, OnInit } from '@angular/core';
2
+import { LoginApiService } from '../services/login-api';
3
+import { Router } from '@angular/router';
2
 
4
 
3
 @Component({
5
 @Component({
4
   selector: 'auth-layout',
6
   selector: 'auth-layout',
5
   template: `
7
   template: `
6
-    <ngx-one-column-layout>
7
-        <router-outlet></router-outlet>
8
-    </ngx-one-column-layout>
8
+    <ngx-one-column-no-sidebar-layout>
9
+      <router-outlet></router-outlet>
10
+    </ngx-one-column-no-sidebar-layout>
9
   `,
11
   `,
10
 })
12
 })
11
-export class AuthComponent {
12
-    
13
+
14
+export class AuthComponent implements OnInit{
15
+  constructor(
16
+    private loginSvc : LoginApiService,
17
+    private router: Router  
18
+  ){}
19
+
20
+  ngOnInit(){
21
+  }
13
 }
22
 }

+ 10
- 0
src/frontend/src/app/frontcraft/auth/auth-routing.module.ts View File

2
 import { RouterModule, Routes } from '@angular/router';
2
 import { RouterModule, Routes } from '@angular/router';
3
 import { MyLoginComponent } from './login/login.component';
3
 import { MyLoginComponent } from './login/login.component';
4
 import { AuthComponent } from './auth-layout.component';
4
 import { AuthComponent } from './auth-layout.component';
5
+import { LogoutComponent } from './logout/logout.component';
6
+import { RegisterComponent } from './register/register.component';
5
 
7
 
6
 export const routes: Routes = [
8
 export const routes: Routes = [
7
     {
9
     {
8
         path: '',
10
         path: '',
9
         component: AuthComponent,
11
         component: AuthComponent,
10
         children: [
12
         children: [
13
+            {
14
+                path: 'register',
15
+                component: RegisterComponent
16
+            },
17
+            {
18
+                path: 'logout',
19
+                component: LogoutComponent,
20
+            },
11
             {
21
             {
12
                 path: '**',
22
                 path: '**',
13
                 component: MyLoginComponent,
23
                 component: MyLoginComponent,

+ 9
- 2
src/frontend/src/app/frontcraft/auth/auth.module.ts View File

8
   NbButtonModule,
8
   NbButtonModule,
9
   NbCheckboxModule,
9
   NbCheckboxModule,
10
   NbInputModule,
10
   NbInputModule,
11
-  NbMenuModule
11
+  NbMenuModule,
12
+  NbCardModule,
13
+  NbSelectModule
12
 } from '@nebular/theme';
14
 } from '@nebular/theme';
13
 import { MyAuthRoutingModule } from './auth-routing.module';
15
 import { MyAuthRoutingModule } from './auth-routing.module';
14
 import { MyLoginComponent } from './login/login.component';
16
 import { MyLoginComponent } from './login/login.component';
17
 import { DashboardModule } from '../../demo_pages/dashboard/dashboard.module';
19
 import { DashboardModule } from '../../demo_pages/dashboard/dashboard.module';
18
 import { ECommerceModule } from '../../demo_pages/e-commerce/e-commerce.module';
20
 import { ECommerceModule } from '../../demo_pages/e-commerce/e-commerce.module';
19
 import { MiscellaneousModule } from '../../demo_pages/miscellaneous/miscellaneous.module';
21
 import { MiscellaneousModule } from '../../demo_pages/miscellaneous/miscellaneous.module';
22
+import { LogoutComponent } from './logout/logout.component';
23
+import { RegisterComponent } from './register/register.component';
20
 
24
 
21
 
25
 
22
 @NgModule({
26
 @NgModule({
34
     DashboardModule,
38
     DashboardModule,
35
     ECommerceModule,
39
     ECommerceModule,
36
     MiscellaneousModule,
40
     MiscellaneousModule,
37
-
41
+    NbCardModule,
42
+    NbSelectModule
38
   ],
43
   ],
39
   declarations: [
44
   declarations: [
45
+    RegisterComponent,
46
+    LogoutComponent,
40
     AuthComponent,
47
     AuthComponent,
41
     MyLoginComponent
48
     MyLoginComponent
42
   ],
49
   ],

+ 9
- 44
src/frontend/src/app/frontcraft/auth/login/login.component.html View File

1
 <h1 id="title" class="title">Login</h1>
1
 <h1 id="title" class="title">Login</h1>
2
-<p class="sub-title">Hello! Log in with your email.</p>
3
-
4
-<nb-alert *ngIf="showMessages.error && errors?.length && !submitted" outline="danger" role="alert">
5
-  <p class="alert-title"><b>Oh snap!</b></p>
6
-  <ul class="alert-message-list">
7
-    <li *ngFor="let error of errors" class="alert-message">{{ error }}</li>
8
-  </ul>
9
-</nb-alert>
10
-
11
-<nb-alert *ngIf="showMessages.success && messages?.length && !submitted" outline="success" role="alert">
12
-  <p class="alert-title"><b>Hooray!</b></p>
13
-  <ul class="alert-message-list">
14
-    <li *ngFor="let message of messages" class="alert-message">{{ message }}</li>
15
-  </ul>
16
-</nb-alert>
17
 
2
 
18
 <form (ngSubmit)="login()" #form="ngForm" aria-labelledby="title">
3
 <form (ngSubmit)="login()" #form="ngForm" aria-labelledby="title">
19
 
4
 
21
     <label class="label" for="input-email">Email address:</label>
6
     <label class="label" for="input-email">Email address:</label>
22
     <input nbInput
7
     <input nbInput
23
            fullWidth
8
            fullWidth
24
-           [(ngModel)]="user.email"
9
+           [(ngModel)]="user.name"
25
            #email="ngModel"
10
            #email="ngModel"
26
-           name="email"
11
+           name="name"
27
            id="input-email"
12
            id="input-email"
28
-           pattern=".+@.+\..+"
29
-           placeholder="Email address"
13
+           pattern=".+"
14
+           placeholder="Username"
30
            fieldSize="giant"
15
            fieldSize="giant"
31
            autofocus
16
            autofocus
32
-           [status]="email.dirty ? (email.invalid  ? 'danger' : 'success') : ''"
33
-           [required]="true"
34
-           [attr.aria-invalid]="email.invalid && email.touched ? true : null">
35
-    <ng-container *ngIf="email.invalid && email.touched">
36
-      <p class="error-message" *ngIf="email.errors?.required">
37
-        Email is required!
38
-      </p>
39
-      <p class="error-message" *ngIf="email.errors?.pattern">
40
-        Email should be the real one!
41
-      </p>
42
-    </ng-container>
17
+           [required]="true">
18
+
43
   </div>
19
   </div>
44
 
20
 
45
   <div class="form-control-group">
21
   <div class="form-control-group">
55
            fieldSize="giant"
31
            fieldSize="giant"
56
            [status]="password.dirty ? (password.invalid  ? 'danger' : 'success') : ''"
32
            [status]="password.dirty ? (password.invalid  ? 'danger' : 'success') : ''"
57
            [required]="true"
33
            [required]="true"
58
-           [minlength]="6"
34
+           [minlength]="1"
59
            [maxlength]="15"
35
            [maxlength]="15"
60
            [attr.aria-invalid]="password.invalid && password.touched ? true : null">
36
            [attr.aria-invalid]="password.invalid && password.touched ? true : null">
61
-    <ng-container *ngIf="password.invalid && password.touched ">
62
-      <p class="error-message" *ngIf="password.errors?.required">
63
-        Password is required!
64
-      </p>
65
-      <p class="error-message" *ngIf="password.errors?.minlength || password.errors?.maxlength">
66
-        Password should contains
67
-        from {{ 6 }}
68
-        to {{ 15 }}
69
-        characters
70
-      </p>
71
-    </ng-container>
72
   </div>
37
   </div>
73
 
38
 
74
   <div class="form-control-group accept-group">
39
   <div class="form-control-group accept-group">
88
 
53
 
89
 
54
 
90
 <section class="another-action" aria-label="Register">
55
 <section class="another-action" aria-label="Register">
91
-  Don't have an account? <a class="text-link" routerLink="../register">Register</a>
92
-</section>
56
+  Don't have an account? <a class="text-link" routerLink="/auth/register">Register</a>
57
+</section>

+ 8
- 1
src/frontend/src/app/frontcraft/auth/login/login.component.ts View File

25
   ){}
25
   ){}
26
 
26
 
27
   ngOnInit(){
27
   ngOnInit(){
28
-      console.log(this.router)
28
+    this.loginApi.checkLogin().then(loggedin => {
29
+      if(loggedin){
30
+        this.router.navigateByUrl("/")
31
+      }
32
+    });
29
   }
33
   }
30
 
34
 
35
+  login(){
36
+    this.loginApi.login(this.user.name, this.user.password)
37
+  }
31
 }
38
 }

+ 1
- 0
src/frontend/src/app/frontcraft/auth/logout/logout.component.html View File

1
+You will be redirected shortly. If not click here <a href="/auth/login">click</a>

+ 19
- 0
src/frontend/src/app/frontcraft/auth/logout/logout.component.ts View File

1
+import { Component, OnInit } from '@angular/core';
2
+import { LoginApiService } from '../../services/login-api';
3
+import { Router } from '@angular/router';
4
+
5
+@Component({
6
+  selector: 'mylogout',
7
+  templateUrl: './logout.component.html',
8
+})
9
+export class LogoutComponent implements OnInit{
10
+
11
+  constructor(
12
+    private loginApi : LoginApiService
13
+  ){}
14
+
15
+  ngOnInit(){
16
+    this.loginApi.logout()
17
+  }
18
+
19
+}

+ 89
- 0
src/frontend/src/app/frontcraft/auth/register/register.component.html View File

1
+<h1 id="title" class="title">Account application</h1>
2
+
3
+<form (ngSubmit)="register()" #form="ngForm" aria-labelledby="title">
4
+
5
+  <div class="form-control-group">
6
+    <label class="label" for="input-email">Email address:</label>
7
+    <input nbInput
8
+           fullWidth
9
+           [(ngModel)]="user.email"
10
+           #email="ngModel"
11
+           name="name"
12
+           id="input-email"
13
+           pattern=".+"
14
+           placeholder="Email Address"
15
+           fieldSize="giant"
16
+           autofocus
17
+           [required]="true">
18
+  </div>
19
+
20
+  <div class="form-control-group">
21
+    <label class="label" for="input-username">Username:</label>
22
+    <input nbInput
23
+           fullWidth
24
+           [(ngModel)]="user.name"
25
+           #email="ngModel"
26
+           name="name"
27
+           id="input-username"
28
+           pattern=".+"
29
+           placeholder="Username"
30
+           fieldSize="giant"
31
+           autofocus
32
+           [required]="true">
33
+  </div>
34
+
35
+  <div class="form-control-group">
36
+    <label class="label" for="input-password">Password:</label>
37
+    <input nbInput
38
+           fullWidth
39
+           [(ngModel)]="user.password"
40
+           #password="ngModel"
41
+           name="password"
42
+           type="password"
43
+           id="input-password"
44
+           placeholder="Password"
45
+           fieldSize="giant"
46
+           [status]="password.dirty ? (password.invalid  ? 'danger' : 'success') : ''"
47
+           [required]="true"
48
+           [minlength]="1"
49
+           [maxlength]="15"
50
+           [attr.aria-invalid]="password.invalid && password.touched ? true : null">
51
+  </div>
52
+
53
+  <div class="form-control-group accept-group">
54
+    <nb-checkbox name="rememberMe" [(ngModel)]="user.rememberMe" *ngIf="rememberMe">Remember me</nb-checkbox>
55
+  </div>
56
+
57
+  <nb-card>
58
+    <nb-card-body>
59
+      <nb-checkbox [(ngModel)]="showApplication" name="amMember" #checkbox>I am already a member</nb-checkbox>
60
+      <br />
61
+      <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
+          
65
+        </nb-select>
66
+      </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
69
+        <textarea nbInput fullWidth placeholder="reason" style="min-height: 400px"></textarea>
70
+
71
+      </span>
72
+
73
+    </nb-card-body>
74
+  </nb-card>
75
+
76
+  <button nbButton
77
+          fullWidth
78
+          status="primary"
79
+          size="giant"
80
+          [disabled]="submitted || !form.valid"
81
+          [class.btn-pulse]="submitted">
82
+    Log In
83
+  </button>
84
+</form>
85
+
86
+
87
+<section class="another-action" aria-label="Register">
88
+  Back to <a class="text-link" routerLink="auth/login">Login</a>
89
+</section>

+ 32
- 0
src/frontend/src/app/frontcraft/auth/register/register.component.ts View File

1
+import { Component, OnInit } from '@angular/core';
2
+import { LoginApiService } from '../../services/login-api';
3
+import { Router } from '@angular/router';
4
+import { _Rank } from '../../../../../../backend/Types/Types'
5
+
6
+@Component({
7
+  selector: 'register',
8
+  templateUrl: './register.component.html',
9
+})
10
+export class RegisterComponent implements OnInit{
11
+
12
+  user: any = {};
13
+  showApplication = false
14
+  ranks = _Rank
15
+
16
+  constructor(
17
+    private router : Router,  
18
+    private loginApi : LoginApiService
19
+  ){}
20
+
21
+  ngOnInit(){
22
+    this.loginApi.checkLogin().then(loggedin => {
23
+      if(loggedin){
24
+        this.router.navigateByUrl("/")
25
+      }
26
+    });
27
+  }
28
+
29
+  login(){
30
+    this.loginApi.login(this.user.name, this.user.password)
31
+  }
32
+}

+ 25
- 10
src/frontend/src/app/frontcraft/pages/pages-layout.component.ts View File

1
-import { Component } from '@angular/core';
1
+import { Component, AfterContentChecked, OnInit } from '@angular/core';
2
 import { NbMenuItem } from '@nebular/theme';
2
 import { NbMenuItem } from '@nebular/theme';
3
+import { LoginApiService } from '../services/login-api';
4
+import { Router } from '@angular/router';
3
 
5
 
4
 @Component({
6
 @Component({
5
-  selector: 'auth-layout',
7
+  selector: 'page-layout',
6
   template: `
8
   template: `
7
 
9
 
8
     <ngx-one-column-layout>
10
     <ngx-one-column-layout>
12
     </ngx-one-column-layout>
14
     </ngx-one-column-layout>
13
   `,
15
   `,
14
 })
16
 })
15
-export class PagesLayoutComponent {
16
-    menu:NbMenuItem[] = [{
17
-      icon: 'cube-outline',
18
-      title: 'test'
19
-    },{
20
-      icon: 'globe-2-outline',
21
-      title: 'test2'
22
-    }]
17
+export class PagesLayoutComponent implements OnInit{
18
+  menu:NbMenuItem[] = [{
19
+    icon: 'people-outline',
20
+    title: 'People'
21
+  },{
22
+    icon: 'clock-outline',
23
+    title: 'Raids'
24
+  }]
25
+  
26
+  constructor(
27
+    private loginSvc : LoginApiService,
28
+    private router : Router
29
+  ){}
30
+
31
+  ngOnInit() : void {
32
+    this.loginSvc.checkLogin().then(loggedin => {
33
+      if(!loggedin){
34
+        this.router.navigateByUrl("/auth")
35
+      }
36
+    });
37
+  }
23
 }
38
 }

+ 4
- 2
src/frontend/src/app/frontcraft/pages/pages.module.ts View File

8
   NbButtonModule,
8
   NbButtonModule,
9
   NbCheckboxModule,
9
   NbCheckboxModule,
10
   NbInputModule,
10
   NbInputModule,
11
-  NbMenuModule
11
+  NbMenuModule,
12
+  NbCardModule
12
 } from '@nebular/theme';
13
 } from '@nebular/theme';
13
 import { MyAuthRoutingModule } from './pages-routing.module';
14
 import { MyAuthRoutingModule } from './pages-routing.module';
14
 import { FrontcraftDashboardComponent } from './dashboard/dashboard.component';
15
 import { FrontcraftDashboardComponent } from './dashboard/dashboard.component';
34
     DashboardModule,
35
     DashboardModule,
35
     ECommerceModule,
36
     ECommerceModule,
36
     MiscellaneousModule,
37
     MiscellaneousModule,
37
-
38
+    NbCardModule,
39
+    
38
   ],
40
   ],
39
   declarations: [
41
   declarations: [
40
     PagesLayoutComponent,
42
     PagesLayoutComponent,

+ 74
- 54
src/frontend/src/app/frontcraft/services/login-api.ts View File

1
-import { Injectable } from "@angular/core";
1
+import { Injectable, Injector, NgZone } from "@angular/core";
2
 import {RPCSocket} from 'rpclibrary/js/src/Frontend'
2
 import {RPCSocket} from 'rpclibrary/js/src/Frontend'
3
 
3
 
4
 import { Token, Auth, User, _Class, FrontcraftFeatureIfc, SomeOf, FrontcraftIfc, } from '../../../../../backend/Types/Types'
4
 import { Token, Auth, User, _Class, FrontcraftFeatureIfc, SomeOf, FrontcraftIfc, } from '../../../../../backend/Types/Types'
5
 import { CookieService } from 'ngx-cookie-service';
5
 import { CookieService } from 'ngx-cookie-service';
6
+import { Router } from '@angular/router';
6
 
7
 
7
 @Injectable()
8
 @Injectable()
8
 export class LoginApiService{
9
 export class LoginApiService{
11
     private privSocket: RPCSocket & SomeOf<FrontcraftFeatureIfc>
12
     private privSocket: RPCSocket & SomeOf<FrontcraftFeatureIfc>
12
 
13
 
13
     constructor(
14
     constructor(
14
-        private cookieSvc : CookieService
15
+        private injector: Injector,
16
+        private cookieSvc : CookieService,
17
+        private ngZone : NgZone
15
     ){}
18
     ){}
16
 
19
 
17
     getUnprivilegedSocket = () : RPCSocket & FrontcraftIfc => this.socket
20
     getUnprivilegedSocket = () : RPCSocket & FrontcraftIfc => this.socket
18
 
21
 
19
     private getPrivilegedSocket = async (auth:Auth) : Promise<RPCSocket & SomeOf<FrontcraftFeatureIfc>> => {
22
     private getPrivilegedSocket = async (auth:Auth) : Promise<RPCSocket & SomeOf<FrontcraftFeatureIfc>> => {
20
         if(this.privSocket) return this.privSocket
23
         if(this.privSocket) return this.privSocket
21
-        if(auth.user.rank === 'Guest'){
22
-            return await RPCSocket.makeSocket<SomeOf<FrontcraftFeatureIfc>>(
23
-                20001,
24
-                window.location.hostname
25
-            )
26
-        }
24
+        if(auth == null) throw new Error("Bad Auth")
25
+
27
         try{
26
         try{
28
-            const sock = await RPCSocket.makeSocket<SomeOf<FrontcraftFeatureIfc>>(
27
+            const sock = new RPCSocket(
29
                 auth.port, 
28
                 auth.port, 
30
-                window.location.hostname, 
31
-                auth.token.value
29
+                window.location.hostname
32
             )
30
             )
31
+           
32
+            const authSock = await sock.connect<RPCSocket & SomeOf<FrontcraftFeatureIfc>>(auth.token.value)
33
+
34
+            sock.hook('kick', () => this.logout())
35
+            sock.hook('getUserData', () => auth)
36
+            sock.hook('navigate', (where:string) => {
37
+                this.ngZone.run(() => {
38
+                    this.injector.get(Router).navigateByUrl(where);
39
+                })
40
+            })
41
+            sock.on('error', (e) => {
42
+                console.log('Socket error',  e)
43
+                this.logout()
44
+            })
33
 
45
 
34
-            //login success
35
             this.auth = auth
46
             this.auth = auth
36
-            this.privSocket = sock
37
-            this.setCookie(auth.token)
38
-            return sock
47
+            this.privSocket = authSock
48
+            this.cookieSvc.set('token', JSON.stringify(auth))
49
+            return authSock
39
         }catch(e){ 
50
         }catch(e){ 
40
             //login failed
51
             //login failed
41
-            throw new Error('login failed')
52
+            throw new Error(e)
42
         }
53
         }
43
     }
54
     }
44
 
55
 
45
     getFeature = async <K extends keyof FrontcraftFeatureIfc>(feature : K) : Promise<void | FrontcraftFeatureIfc[K]> => {
56
     getFeature = async <K extends keyof FrontcraftFeatureIfc>(feature : K) : Promise<void | FrontcraftFeatureIfc[K]> => {
46
-        const sock = await this.getPrivilegedSocket(this.auth)
47
-        if(sock[feature]) return <FrontcraftFeatureIfc[K]> sock[feature]
57
+        try{
58
+            const sock = await this.getPrivilegedSocket(this.auth)
59
+            if(sock[feature]) return <FrontcraftFeatureIfc[K]> sock[feature]
60
+        }catch(e){
61
+            return
62
+        }
48
     }
63
     }
49
 
64
 
50
-    getCurrentUser = () : User => this.auth 
51
-                                ? this.auth.user 
52
-                                : { 
53
-                                    name: 'Guest', 
54
-                                    specid: 1, 
55
-                                    pwhash: '',
56
-                                    rank: 'Guest'
57
-                                }
58
-
59
-    authenticate = async (token : Token | string) : Promise<RPCSocket & SomeOf<FrontcraftFeatureIfc>> => {
60
-        const auth = await this.socket.Authenticator.authenticate(token)
61
-        return await this.getPrivilegedSocket(auth)
62
-    }
65
+    getCurrentUser = () : User | undefined => this.auth?this.auth.user:undefined
63
 
66
 
64
-    login = async (username: string, password: string) => {
67
+    login = async (username: string, password: string) : Promise<RPCSocket & SomeOf<FrontcraftFeatureIfc>> => {
65
         const buf = str2arraybuf(password)
68
         const buf = str2arraybuf(password)
66
         const pwHash = await crypto.subtle.digest('SHA-256', buf);
69
         const pwHash = await crypto.subtle.digest('SHA-256', buf);
67
-        const token = await this.socket.Authenticator.login(username, buf2hex(pwHash))
68
-        return await this.authenticate(token)
70
+
71
+        const auth = await this.socket.Authenticator.login(username, buf2hex(pwHash))
72
+
73
+
74
+        if(!auth){ 
75
+            await this.logout()
76
+            throw new Error("Login failed")
77
+        }
78
+        const sock = await this.getPrivilegedSocket(auth)
79
+        return sock
69
     }
80
     }
70
 
81
 
71
-    logout = () => {
72
-        this.cookieSvc.deleteAll()
73
-        this.auth  = null
82
+    logout = async () => {
83
+        this.cookieSvc.set('token', undefined)
84
+        if(this.auth) await this.socket.Authenticator.logout(this.auth.user.name, this.auth.token.value)
74
         if(this.privSocket) this.privSocket.destroy()
85
         if(this.privSocket) this.privSocket.destroy()
75
         this.privSocket = null
86
         this.privSocket = null
87
+        this.auth  = null
88
+        this.ngZone.run(() => {
89
+            this.injector.get(Router).navigate(['/auth']);
90
+        })
76
     }
91
     }
77
 
92
 
78
-    private setCookie = (token: string | Token) => {
79
-        token = 'string' === typeof token? token : token.value 
80
-        this.cookieSvc.set('token', token)
81
-    }
82
-
83
-    private getCookie = () : string | Token | undefined => {
84
-        return this.cookieSvc.get('token')
85
-    }
86
 
93
 
87
-    initialize = async () : Promise<RPCSocket> => {
94
+    initialize = async () : Promise<any> => {
88
         const sock = await RPCSocket.makeSocket<FrontcraftIfc>(20000, window.location.hostname)
95
         const sock = await RPCSocket.makeSocket<FrontcraftIfc>(20000, window.location.hostname)
89
         this.socket = sock
96
         this.socket = sock
90
-
91
-        const cookie = this.getCookie()
92
-        if(cookie) {
93
-            try{
94
-                return await this.authenticate(cookie)
95
-            }catch(e){
96
-                this.logout()
97
+        try{
98
+            const cookie = JSON.parse(this.cookieSvc.get('token'))
99
+            if(cookie != null) {
100
+                try{
101
+                    const auth = await sock.Authenticator.getAuth(cookie.token.value)
102
+                    if(!auth) return sock
103
+                    return await this.getPrivilegedSocket(auth)
104
+                }catch(e){
105
+                    await this.logout()
106
+                    return
107
+                }
97
             }
108
             }
109
+        }catch(e){
98
         }
110
         }
111
+    }
99
 
112
 
100
-        return sock
113
+    getAuth = () => this.auth
114
+
115
+    async checkLogin() : Promise<boolean>{
116
+        if(!this.auth) return false
117
+        const valid = await this.socket.Authenticator.checkToken(this.auth.token.value, this.auth.user.rank)
118
+        if(valid) return true
119
+        await this.logout()
120
+        return false
101
     }
121
     }
102
 }
122
 }
103
 
123
 

Loading…
Cancel
Save