rework login and make register
This commit is contained in:
Generated
+3
-3
@@ -4961,9 +4961,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rpclibrary": {
|
"rpclibrary": {
|
||||||
"version": "1.4.1",
|
"version": "1.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.5.2.tgz",
|
||||||
"integrity": "sha512-Tv9zOBVT8JFMZfTJgmnX9vvUvtALCDtj/cnlYw2SxsFnj1MuH9VgPniSfThUgdwZZknjFuYVfhLaYb9Yl+eRxQ==",
|
"integrity": "sha512-BI08DxIcndBf25Rd1k957cTfxhNO9Mr1Y3YBSEuYG2dzI5x2/+T83N3swTn68esjLlzvbcmqMHncd5sCsVmN8w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"bsock": "^0.1.9",
|
"bsock": "^0.1.9",
|
||||||
"http": "0.0.0",
|
"http": "0.0.0",
|
||||||
|
|||||||
+1
-1
@@ -37,7 +37,7 @@
|
|||||||
"node-fetch": "^2.6.0",
|
"node-fetch": "^2.6.0",
|
||||||
"path": "^0.12.7",
|
"path": "^0.12.7",
|
||||||
"rimraf": "^3.0.0",
|
"rimraf": "^3.0.0",
|
||||||
"rpclibrary": "^1.4.1",
|
"rpclibrary": "^1.5.2",
|
||||||
"simple-git": "^1.124.0",
|
"simple-git": "^1.124.0",
|
||||||
"spawn-sync": "^2.0.0",
|
"spawn-sync": "^2.0.0",
|
||||||
"sqlite3": "^4.1.0",
|
"sqlite3": "^4.1.0",
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export class FrontworkAdmin
|
|||||||
implements TableDefinitionExporter {
|
implements TableDefinitionExporter {
|
||||||
knex:Knex
|
knex:Knex
|
||||||
config: RPCConfigLoader<AdminConf>
|
config: RPCConfigLoader<AdminConf>
|
||||||
|
rpcServer: RPCServer
|
||||||
|
|
||||||
private express
|
private express
|
||||||
private httpServer
|
private httpServer
|
||||||
@@ -75,7 +76,7 @@ implements TableDefinitionExporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private startWebsocket(){
|
private startWebsocket(){
|
||||||
new RPCServer(20000, [
|
this.rpcServer = new RPCServer(20000, [
|
||||||
...this.components,
|
...this.components,
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,15 +73,13 @@ implements RPCExporter<EventbusIfc, "Eventbus">, TableDefinitionExporter {
|
|||||||
exportRPCs(){
|
exportRPCs(){
|
||||||
return [{
|
return [{
|
||||||
name: 'getNotificationLog' as 'getNotificationLog',
|
name: 'getNotificationLog' as 'getNotificationLog',
|
||||||
call: async () => await this.getNotificationLog()
|
call: this.getNotificationLog
|
||||||
},{
|
},{
|
||||||
name: 'pushNotification' as 'pushNotification',
|
name: 'pushNotification' as 'pushNotification',
|
||||||
call: async (notification: Notification) => { return await this.pushNotification(notification) }
|
call: this.pushNotification
|
||||||
},{
|
},{
|
||||||
name: 'subscribeNotificaitons' as 'subscribeNotifications',
|
name: 'subscribeNotificaitons' as 'subscribeNotifications',
|
||||||
hook: async (callback: Function) => {
|
hook: async (callback: Function) => await this.subscribeNotifications(callback)
|
||||||
return await this.subscribeNotifications(callback)
|
|
||||||
}
|
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ implements FrontworkComponent<GuildManagerIfc, GuildManagerFeatureIfc>{
|
|||||||
|
|
||||||
exportRPCs = () => [{
|
exportRPCs = () => [{
|
||||||
name: 'getHeadCount' as 'getHeadCount',
|
name: 'getHeadCount' as 'getHeadCount',
|
||||||
call: async () => await this.headCount()
|
call: this.headCount
|
||||||
},{
|
},{
|
||||||
name: 'getGuildInfo' as 'getGuildInfo',
|
name: 'getGuildInfo' as 'getGuildInfo',
|
||||||
call: async () => this.guild.getConfig()
|
call: async () => this.guild.getConfig()
|
||||||
|
|||||||
@@ -29,10 +29,10 @@ implements FrontworkComponent<ItemManagerIfc, ItemManagerFeatureIfc>, TableDefin
|
|||||||
exportRPCs(): RPC<any, any>[]{
|
exportRPCs(): RPC<any, any>[]{
|
||||||
return [{
|
return [{
|
||||||
name: 'getItems',
|
name: 'getItems',
|
||||||
call: async () => await this.getItems()
|
call: this.getItems
|
||||||
},{
|
},{
|
||||||
name: 'getItem',
|
name: 'getItem',
|
||||||
call: async (name:string) => await this.getItem(name)
|
call: this.getItem
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -146,22 +146,22 @@ implements RPCExporter<PluginLoaderIfc, "PluginLoader">{
|
|||||||
exportRPCs(){
|
exportRPCs(){
|
||||||
return [{
|
return [{
|
||||||
name: "installPlugin" as "installPlugin",
|
name: "installPlugin" as "installPlugin",
|
||||||
call: async (name:string, force = false) => {return await this.installPlugin(name, force)},
|
call: this.installPlugin,
|
||||||
},{
|
},{
|
||||||
name: "startPlugin" as "startPlugin",
|
name: "startPlugin" as "startPlugin",
|
||||||
call: async (name:string) => {return await this.startPlugin(name)},
|
call: this.startPlugin,
|
||||||
},{
|
},{
|
||||||
name: "updatePlugin" as "updatePlugin",
|
name: "updatePlugin" as "updatePlugin",
|
||||||
call: async (name:string) => {return await this.updatePlugin(name)},
|
call: this.updatePlugin,
|
||||||
},{
|
},{
|
||||||
name: "setPluginVersion" as "setPluginVersion",
|
name: "setPluginVersion" as "setPluginVersion",
|
||||||
call: async (name:string, tag:string) => {return await this.setPluginVersion(name, tag)},
|
call: this.setPluginVersion,
|
||||||
},{
|
},{
|
||||||
name: "getLoadedPluginNames" as "getLoadedPluginNames",
|
name: "getLoadedPluginNames" as "getLoadedPluginNames",
|
||||||
call: async () => {return this.getPlugins().map(p => p.name)},
|
call: async () => this.getPlugins().map(p => p.name),
|
||||||
},{
|
},{
|
||||||
name: "selfUpdate" as "selfUpdate",
|
name: "selfUpdate" as "selfUpdate",
|
||||||
call: async (force: boolean) => {return await this.selfUpdate(force)},
|
call: this.selfUpdate,
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -21,22 +21,22 @@ implements RPCExporter<ConfigLoaderIfc<ConfT>, "Config">{
|
|||||||
exportRPCs() {
|
exportRPCs() {
|
||||||
return [{
|
return [{
|
||||||
name: "getConfig" as "getConfig",
|
name: "getConfig" as "getConfig",
|
||||||
call: () => { return this.getConfig() }
|
call: this.getConfig
|
||||||
},{
|
},{
|
||||||
name: "resetConfig" as "resetConfig",
|
name: "resetConfig" as "resetConfig",
|
||||||
call: () => { return this.resetConfig() }
|
call: this.resetConfig
|
||||||
},{
|
},{
|
||||||
name: "setConfig" as "setConfig",
|
name: "setConfig" as "setConfig",
|
||||||
call: (conf:ConfT) => { return this.setConfig(conf) }
|
call: this.setConfig
|
||||||
},{
|
},{
|
||||||
name: "setConfigKey" as "setConfigKey",
|
name: "setConfigKey" as "setConfigKey",
|
||||||
call: (key:string, value:any) => { return this.setConfigKey(key, value) }
|
call: this.setConfigKey
|
||||||
},{
|
},{
|
||||||
name: "deleteConfigKey" as "deleteConfigKey",
|
name: "deleteConfigKey" as "deleteConfigKey",
|
||||||
call: (key:string) => { return this.deleteConfigKey(key) }
|
call: this.deleteConfigKey
|
||||||
},{
|
},{
|
||||||
name: "getConfigKey" as "getConfigKey",
|
name: "getConfigKey" as "getConfigKey",
|
||||||
call: (key:string) => { return this.getConfigKey(key) }
|
call: this.getConfigKey
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,25 +15,25 @@ implements FrontworkComponent<RaidManagerIfc, RaidManagerFeatureIfc>{
|
|||||||
name: 'manageRaid' as 'manageRaid',
|
name: 'manageRaid' as 'manageRaid',
|
||||||
exportRPCs: () => [{
|
exportRPCs: () => [{
|
||||||
name: 'createRaid' as 'createRaid',
|
name: 'createRaid' as 'createRaid',
|
||||||
call: async (raid:Raid) => await this.createRaid(raid)
|
call: this.createRaid
|
||||||
},{
|
},{
|
||||||
name: 'addSignup' as 'addSignup',
|
name: 'addSignup' as 'addSignup',
|
||||||
call: async(signup: Signup) => await this.addSignup(signup)
|
call: this.addSignup
|
||||||
},{
|
},{
|
||||||
name: 'removeSignup' as 'removeSignup',
|
name: 'removeSignup' as 'removeSignup',
|
||||||
call: async(signup: Signup) => await this.removeSignup(signup)
|
call: this.removeSignup
|
||||||
}]
|
}]
|
||||||
},{
|
},{
|
||||||
name: 'signup' as 'signup',
|
name: 'signup' as 'signup',
|
||||||
exportRPCs: () => [{
|
exportRPCs: () => [{
|
||||||
name: 'getRaids' as 'getRaids',
|
name: 'getRaids' as 'getRaids',
|
||||||
call: async () => await this.getRaids()
|
call: this.getRaids
|
||||||
},{
|
},{
|
||||||
name: 'getSingups' as 'getSingups',
|
name: 'getSingups' as 'getSingups',
|
||||||
call: async(raid: Raid) => await this.getSignups(raid)
|
call: this.getSignups
|
||||||
},{
|
},{
|
||||||
name: 'sign' as 'sign',
|
name: 'sign' as 'sign',
|
||||||
call: async(user:User, raid:Raid) => await this.sign(user, raid)
|
call: this.sign
|
||||||
}]
|
}]
|
||||||
},]
|
},]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,291 @@
|
|||||||
|
import { RPCServer, Socket } from "rpclibrary";
|
||||||
|
import { TableDefiniton, AnyRPCExporter, User, RPCPermission, Token, Auth, Rank, FrontcraftFeatureIfc, _Rank } from "../../Types/Types";
|
||||||
|
import { FrontworkAdmin } from "../../Admin/Admin";
|
||||||
|
import { PrivilegedRPCExporter } from "../../Types/PrivilegedRPCExporter";
|
||||||
|
import { FrontworkComponent } from "../../Types/FrontworkComponent";
|
||||||
|
import { getSpecTableData } from "../../Types/PlayerSpecs"
|
||||||
|
import { LoginManagerIfc, LoginManagerFeatureIfc } from "./RPCInterface";
|
||||||
|
const uuid = require('uuid/v4')
|
||||||
|
|
||||||
|
const ONE_WEEK = 604800000
|
||||||
|
|
||||||
|
type Serverstate = {
|
||||||
|
server: RPCServer,
|
||||||
|
port : number,
|
||||||
|
allowed: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LoginManager
|
||||||
|
implements FrontworkComponent<LoginManagerIfc, LoginManagerFeatureIfc>{
|
||||||
|
name = "Authenticator" as "Authenticator";
|
||||||
|
admin:FrontworkAdmin
|
||||||
|
|
||||||
|
rankServers : {[rank in Rank] : Serverstate}
|
||||||
|
userLogins : {[username in string] : {
|
||||||
|
connections: {[port in number]: Socket}
|
||||||
|
auth: Auth
|
||||||
|
}} = {}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private exporters: PrivilegedRPCExporter[]
|
||||||
|
){}
|
||||||
|
|
||||||
|
exportRPCs = () => [
|
||||||
|
{
|
||||||
|
name: 'login' as 'login',
|
||||||
|
call: this.login
|
||||||
|
},{
|
||||||
|
name: 'logout' as 'logout',
|
||||||
|
call: this.logout
|
||||||
|
},{
|
||||||
|
name: 'getAuth' as 'getAuth',
|
||||||
|
call: this.getAuth
|
||||||
|
},{
|
||||||
|
name: 'checkToken' as 'checkToken',
|
||||||
|
call: async (tokenValue : string, rank: Rank) => this.checkToken(tokenValue, rank)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
onSetAdmin(admin:FrontworkAdmin){
|
||||||
|
this.exporters.forEach(e => e['admin'] = admin)
|
||||||
|
}
|
||||||
|
|
||||||
|
exportRPCFeatures = () => [
|
||||||
|
{
|
||||||
|
name: 'createUser' as 'createUser',
|
||||||
|
exportRPCs: () => [{
|
||||||
|
name: 'createUser' as 'createUser',
|
||||||
|
call: this.createUser
|
||||||
|
}]
|
||||||
|
},{
|
||||||
|
name: 'modifyPermissions' as 'modifyPermissions',
|
||||||
|
exportRPCs: () => [{
|
||||||
|
name: 'getPermissions' as 'getPermissions',
|
||||||
|
call: this.getPermissions
|
||||||
|
},{
|
||||||
|
name: 'setPermission' as 'setPermission',
|
||||||
|
call: this.setPermission
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
getTableDefinitions = (): TableDefiniton[] => [
|
||||||
|
{
|
||||||
|
name: 'users',
|
||||||
|
tableBuilder: (table) => {
|
||||||
|
table.increments("id").primary()
|
||||||
|
table.string("name").notNullable().unique()
|
||||||
|
table.string("pwhash").notNullable()
|
||||||
|
table.string("rank").notNullable()
|
||||||
|
table.string("email").nullable().unique()
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
name: 'characters',
|
||||||
|
tableBuilder: (table) => {
|
||||||
|
table.increments("id").primary()
|
||||||
|
table.string("name").notNullable().unique()
|
||||||
|
table.integer("specid").notNullable()
|
||||||
|
table.foreign("specid").references("specs.id")
|
||||||
|
table.integer("userid").notNullable()
|
||||||
|
table.foreign("userid").references("users.id")
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
name: 'rpcpermissions',
|
||||||
|
tableBuilder: (table) => {
|
||||||
|
table.string("name").primary().notNullable()
|
||||||
|
table.boolean("ADMIN").defaultTo(true).notNullable()
|
||||||
|
_Rank.forEach(r => table.boolean(r).defaultTo(false).notNullable())
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
name: 'specs',
|
||||||
|
tableBuilder: (table) => {
|
||||||
|
table.increments("id")
|
||||||
|
table.string('class')
|
||||||
|
table.string('name')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
,...this.exporters.flatMap(exp => exp['getTableDefinitions']?exp['getTableDefinitions']():undefined)
|
||||||
|
]
|
||||||
|
|
||||||
|
initialize = async () => {
|
||||||
|
//set up permissions
|
||||||
|
await Promise.all(
|
||||||
|
[this, ...this.exporters].flatMap(exp => exp.exportRPCFeatures().map(async (feature) => {
|
||||||
|
try{
|
||||||
|
await this.admin.knex.insert({ name: feature.name }).into('rpcpermissions')
|
||||||
|
}catch(e){}
|
||||||
|
})))
|
||||||
|
|
||||||
|
//initialize managed exporters
|
||||||
|
await Promise.all(this.exporters.map(ex => ex['initialize']?ex['initialize']():undefined))
|
||||||
|
|
||||||
|
//initialize spec table
|
||||||
|
await this.admin.knex('specs').insert(getSpecTableData()).catch(e => { console.log("skipping spec insertion") })
|
||||||
|
|
||||||
|
//start rankServers
|
||||||
|
const rankServers : any = {}
|
||||||
|
|
||||||
|
for(let i = 0; i < _Rank.length; i++){
|
||||||
|
const rank:Rank = _Rank[i]
|
||||||
|
const port = 20001 + i
|
||||||
|
const rankServer = await this.startRankServer(rank, port)
|
||||||
|
rankServers[rank] = {
|
||||||
|
server: rankServer,
|
||||||
|
port: port,
|
||||||
|
allowed: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.rankServers = rankServers
|
||||||
|
|
||||||
|
setInterval(this.checkExpiredSessions, 600_000)
|
||||||
|
}
|
||||||
|
|
||||||
|
checkExpiredSessions = () => {
|
||||||
|
Object.values(this.userLogins).map(userLogin => {
|
||||||
|
const auth = userLogin.auth
|
||||||
|
if(!this.checkToken(auth.token.value, auth.user.rank)){
|
||||||
|
this.logout(auth.user.name, auth.token.value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
checkConnection = async (socket: Socket) => {
|
||||||
|
let data : Auth | false = false
|
||||||
|
while(!data){
|
||||||
|
data = await Promise.race([socket.call('getUserData'), new Promise((res, rej) => { setTimeout(res, 250);})])
|
||||||
|
}
|
||||||
|
this.userLogins[data.user.name].connections[socket.port] = socket
|
||||||
|
await socket.call('navigate', ["/frontcraft/dashboard"])
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
setPermission = async (permission: RPCPermission) => {
|
||||||
|
await this.admin.knex('rpcpermissions')
|
||||||
|
.where('rpcname', '=', permission.name)
|
||||||
|
.update(permission)
|
||||||
|
}
|
||||||
|
|
||||||
|
getPermissions = async () : Promise<RPCPermission[]> => {
|
||||||
|
return await this.admin.knex.select('*').from('rpcpermissions')
|
||||||
|
}
|
||||||
|
|
||||||
|
getPermission = async (feature: keyof FrontcraftFeatureIfc, rank:Rank) : Promise<boolean> => {
|
||||||
|
const perm : RPCPermission[] = await this.admin.knex
|
||||||
|
.select(rank)
|
||||||
|
.from('rpcpermissions')
|
||||||
|
.where('name', '=', <string>feature)
|
||||||
|
|
||||||
|
if(perm.length === 0) return false
|
||||||
|
return perm[0][rank]
|
||||||
|
}
|
||||||
|
|
||||||
|
getRPCForRank = async (rank: Rank): Promise<AnyRPCExporter[]> => {
|
||||||
|
return [
|
||||||
|
...this.exportRPCFeatures(),
|
||||||
|
...this.exporters.flatMap((exp) => exp.exportRPCFeatures())
|
||||||
|
].filter(async (feature) => await this.getPermission(<keyof FrontcraftFeatureIfc> feature.name, rank))
|
||||||
|
}
|
||||||
|
|
||||||
|
createUser = async(user:User): Promise<User> => {
|
||||||
|
await this.admin.knex('users')
|
||||||
|
.insert(user)
|
||||||
|
|
||||||
|
const users = await this.admin.knex
|
||||||
|
.select("*")
|
||||||
|
.from('users')
|
||||||
|
.where(user)
|
||||||
|
return users[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
logout = async (username:string, tokenValue : string) : Promise<void> => {
|
||||||
|
try{
|
||||||
|
|
||||||
|
await Promise.all (Object.values(this.userLogins[username].connections).map(async (sock) => {
|
||||||
|
await sock.call('navigate', '/auth/login')
|
||||||
|
}))
|
||||||
|
|
||||||
|
Object.values(this.rankServers)
|
||||||
|
.forEach(state => {
|
||||||
|
state.allowed = state.allowed.filter(allowed => allowed !== tokenValue)
|
||||||
|
})
|
||||||
|
|
||||||
|
delete this.userLogins[username]
|
||||||
|
}catch(e){
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
login = async(username:string, pwHash:string) : Promise<Auth> => {
|
||||||
|
const res:User[] = await this.admin.knex
|
||||||
|
.select('*')
|
||||||
|
.from('users')
|
||||||
|
.where({ name: username })
|
||||||
|
|
||||||
|
if(res.length > 0 && pwHash === res[0].pwhash){
|
||||||
|
const user:User = res[0]
|
||||||
|
delete user.pwhash
|
||||||
|
|
||||||
|
//return existing auth
|
||||||
|
if(this.userLogins[username] != null){
|
||||||
|
return this.userLogins[username].auth
|
||||||
|
}
|
||||||
|
|
||||||
|
const token = this.createToken(user)
|
||||||
|
const userAuth : Auth = {
|
||||||
|
token: token,
|
||||||
|
user: user,
|
||||||
|
port: this.rankServers[user.rank].port
|
||||||
|
}
|
||||||
|
|
||||||
|
this.userLogins[user.name] = {connections: {}, auth: userAuth}
|
||||||
|
this.rankServers[user.rank].allowed.push(token.value)
|
||||||
|
|
||||||
|
return userAuth
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('login failed')
|
||||||
|
}
|
||||||
|
|
||||||
|
getAuth = async (tokenValue:string) : Promise<Auth> => {
|
||||||
|
const maybeAuth = Object.values(this.userLogins).find(login => login.auth.token.value === tokenValue)
|
||||||
|
if(maybeAuth)
|
||||||
|
return maybeAuth.auth
|
||||||
|
|
||||||
|
throw new Error("Bad token")
|
||||||
|
}
|
||||||
|
|
||||||
|
startRankServer = async (rank : Rank, port: number) : Promise<RPCServer> => {
|
||||||
|
const allowedRPCs = await this.getRPCForRank(rank)
|
||||||
|
let rpcServer : RPCServer = new RPCServer(port, allowedRPCs, {
|
||||||
|
closeHandler: (socket) => {
|
||||||
|
Object.values(this.userLogins)
|
||||||
|
.forEach(login => delete login.connections[socket.port])
|
||||||
|
|
||||||
|
},
|
||||||
|
connectionHandler: (socket) => {
|
||||||
|
this.checkConnection(socket).catch(() => {}) //sometimes times out if you go too fast
|
||||||
|
},
|
||||||
|
sesame: (sesame) => this.checkToken(sesame, rank)
|
||||||
|
})
|
||||||
|
return rpcServer
|
||||||
|
}
|
||||||
|
|
||||||
|
checkToken = (token: string, rank: Rank) : boolean => this.rankServers[rank].allowed.includes(token)
|
||||||
|
&& Object.values(this.userLogins).find(login => login.auth.token.value === token)!.auth.token.created > Date.now() - ONE_WEEK
|
||||||
|
|
||||||
|
createToken = (user:User): Token => {
|
||||||
|
|
||||||
|
if(this.userLogins[user.name]){
|
||||||
|
return this.userLogins[user.name].auth.token
|
||||||
|
}
|
||||||
|
|
||||||
|
const token:Token = {
|
||||||
|
value: uuid(),
|
||||||
|
user_id: user.id!,
|
||||||
|
created: Date.now()
|
||||||
|
}
|
||||||
|
|
||||||
|
return token
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
import { Token, Auth, User, RPCPermission } from "../../Types/Types"
|
import { Token, Auth, User, RPCPermission, Rank } from "../../Types/Types"
|
||||||
|
|
||||||
export type UserManagerIfc = {
|
export type LoginManagerIfc = {
|
||||||
Authenticator: {
|
Authenticator: {
|
||||||
login: (username:string, pwHash:string) => Promise<Token>
|
login: (username:string, pwHash:string) => Promise<Auth>
|
||||||
authenticate: (token:string | Token) => Promise<Auth>
|
logout: (username: string, tokenValue :string) => Promise<void>
|
||||||
|
getAuth: (tokenValue: string) => Promise<Auth>
|
||||||
|
checkToken: (token: string, rank: Rank) => Promise<boolean>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserManagerFeatureIfc = {
|
export type LoginManagerFeatureIfc = {
|
||||||
createUser: {
|
createUser: {
|
||||||
createUser: (user:User) => Promise<User>
|
createUser: (user:User) => Promise<User>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,227 +0,0 @@
|
|||||||
import { RPCServer } from "rpclibrary";
|
|
||||||
import { TableDefiniton, AnyRPCExporter, User, RPCPermission, _Rank, Token, Auth, Rank, FrontcraftFeatureIfc } from "../../Types/Types";
|
|
||||||
import { FrontworkAdmin } from "../../Admin/Admin";
|
|
||||||
import { PrivilegedRPCExporter } from "../../Types/PrivilegedRPCExporter";
|
|
||||||
import { FrontworkComponent } from "../../Types/FrontworkComponent";
|
|
||||||
import { getSpecTableData } from "../../Types/PlayerSpecs"
|
|
||||||
import { UserManagerIfc, UserManagerFeatureIfc } from "./RPCInterface";
|
|
||||||
const uuid = require('uuid/v4')
|
|
||||||
|
|
||||||
export class LoginManager
|
|
||||||
implements FrontworkComponent<UserManagerIfc, UserManagerFeatureIfc>{
|
|
||||||
name = "Authenticator" as "Authenticator";
|
|
||||||
admin:FrontworkAdmin
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private exporters: PrivilegedRPCExporter[]
|
|
||||||
){}
|
|
||||||
|
|
||||||
exportRPCs = () => [
|
|
||||||
{
|
|
||||||
name: 'login' as 'login',
|
|
||||||
call: async (username:string, pwHash:string) => await this.login(username, pwHash)
|
|
||||||
},{
|
|
||||||
name: 'authenticate' as 'authenticate',
|
|
||||||
call: async (tokenValue:string | Token) => await this.authenticate(tokenValue)
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
onSetAdmin(admin:FrontworkAdmin){
|
|
||||||
this.exporters.forEach(e => e['admin'] = admin)
|
|
||||||
}
|
|
||||||
|
|
||||||
exportRPCFeatures = () => [
|
|
||||||
{
|
|
||||||
name: 'createUser' as 'createUser',
|
|
||||||
exportRPCs: () => [{
|
|
||||||
name: 'createUser' as 'createUser',
|
|
||||||
call: async (user:User) => await this.createUser(user)
|
|
||||||
}]
|
|
||||||
},{
|
|
||||||
name: 'modifyPermissions' as 'modifyPermissions',
|
|
||||||
exportRPCs: () => [{
|
|
||||||
name: 'getPermissions' as 'getPermissions',
|
|
||||||
call: async () => await this.getPermissions()
|
|
||||||
},{
|
|
||||||
name: 'setPermission' as 'setPermission',
|
|
||||||
call: async (perm: RPCPermission) => await this.setPermission(perm)
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
getTableDefinitions = (): TableDefiniton[] => [
|
|
||||||
{
|
|
||||||
name: 'users',
|
|
||||||
tableBuilder: (table) => {
|
|
||||||
table.increments("id").primary()
|
|
||||||
table.string("name").notNullable().unique()
|
|
||||||
table.string("pwhash").notNullable()
|
|
||||||
table.string("rank").notNullable()
|
|
||||||
table.string("email").nullable().unique()
|
|
||||||
}
|
|
||||||
},{
|
|
||||||
name: 'characters',
|
|
||||||
tableBuilder: (table) => {
|
|
||||||
table.increments("id").primary()
|
|
||||||
table.string("name").notNullable().unique()
|
|
||||||
table.integer("specid").notNullable()
|
|
||||||
table.foreign("specid").references("specs.id")
|
|
||||||
table.integer("userid").notNullable()
|
|
||||||
table.foreign("userid").references("users.id")
|
|
||||||
}
|
|
||||||
},{
|
|
||||||
name: 'rpcpermissions',
|
|
||||||
tableBuilder: (table) => {
|
|
||||||
table.string("name").primary().notNullable()
|
|
||||||
table.boolean("ADMIN").defaultTo(true).notNullable()
|
|
||||||
_Rank.forEach(r => table.boolean(r).defaultTo(false).notNullable())
|
|
||||||
}
|
|
||||||
},{
|
|
||||||
name: 'tokens',
|
|
||||||
tableBuilder: (table) => {
|
|
||||||
table.string('value').primary()
|
|
||||||
table.integer('user_id').notNullable()
|
|
||||||
table.foreign('user_id').references('users')
|
|
||||||
table.dateTime('created').defaultTo(this.admin.knex.fn.now())
|
|
||||||
}
|
|
||||||
},{
|
|
||||||
name: 'specs',
|
|
||||||
tableBuilder: (table) => {
|
|
||||||
table.string('class')
|
|
||||||
table.string('name')
|
|
||||||
table.primary(['class', 'name'])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
,...this.exporters.flatMap(exp => exp['getTableDefinitions']?exp['getTableDefinitions']():undefined)
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
async initialize(){
|
|
||||||
await Promise.all(
|
|
||||||
[this, ...this.exporters].flatMap(exp => exp.exportRPCFeatures().map(async (feature) => {
|
|
||||||
try{
|
|
||||||
await this.admin.knex.insert({ name: feature.name }).into('rpcpermissions')
|
|
||||||
}catch(e){}
|
|
||||||
})))
|
|
||||||
|
|
||||||
await Promise.all(this.exporters.map(ex => ex['initialize']?ex['initialize']():undefined))
|
|
||||||
|
|
||||||
await this.admin.knex('specs').insert(getSpecTableData()).catch(e => { console.log("skipping spec insertion") })
|
|
||||||
}
|
|
||||||
|
|
||||||
async setPermission(permission: RPCPermission){
|
|
||||||
await this.admin.knex('rpcpermissions')
|
|
||||||
.where('rpcname', '=', permission.name)
|
|
||||||
.update(permission)
|
|
||||||
}
|
|
||||||
|
|
||||||
getPermissions = async () : Promise<RPCPermission[]> => {
|
|
||||||
return await this.admin.knex.select('*').from('rpcpermissions')
|
|
||||||
}
|
|
||||||
|
|
||||||
getPermission = async (feature: keyof FrontcraftFeatureIfc, rank:Rank) : Promise<boolean> => {
|
|
||||||
const perm : RPCPermission[] = await this.admin.knex
|
|
||||||
.select(rank)
|
|
||||||
.from('rpcpermissions')
|
|
||||||
.where('name', '=', <string>feature)
|
|
||||||
|
|
||||||
if(perm.length === 0) return false
|
|
||||||
return perm[0][rank]
|
|
||||||
}
|
|
||||||
|
|
||||||
getRPCForUser = async (user:User): Promise<AnyRPCExporter[]> => {
|
|
||||||
return [
|
|
||||||
...this.exportRPCFeatures(),
|
|
||||||
...this.exporters.flatMap((exp) => exp.exportRPCFeatures())
|
|
||||||
].filter(async (feature) => await this.getPermission(<keyof FrontcraftFeatureIfc> feature.name, user.rank))
|
|
||||||
}
|
|
||||||
|
|
||||||
createUser = async(user:User): Promise<User> => {
|
|
||||||
await this.admin.knex('users')
|
|
||||||
.insert(user)
|
|
||||||
|
|
||||||
const users = await this.admin.knex
|
|
||||||
.select("*")
|
|
||||||
.from('users')
|
|
||||||
.where(user)
|
|
||||||
return users[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
login = async(username:string, pwHash:string) : Promise<Token> => {
|
|
||||||
const res:User[] = await this.admin.knex
|
|
||||||
.select("*")
|
|
||||||
.from('users')
|
|
||||||
.where({ name: username })
|
|
||||||
|
|
||||||
if(res.length > 0 && pwHash === res[0].pwhash){
|
|
||||||
return await this.createToken(res[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error('login failed')
|
|
||||||
}
|
|
||||||
|
|
||||||
authenticate = async(tokenValue: string | Token) : Promise<Auth> => {
|
|
||||||
if(typeof tokenValue !== 'string') tokenValue = tokenValue.value
|
|
||||||
|
|
||||||
const res : User[] = await this.admin.knex
|
|
||||||
.select('users.id', 'name', 'specid', 'rank', 'email')
|
|
||||||
.from('tokens')
|
|
||||||
.join('users', function(){
|
|
||||||
this.on('users.id', '=', 'tokens.user_id')
|
|
||||||
})
|
|
||||||
.where({ value: tokenValue})
|
|
||||||
|
|
||||||
if(res.length === 0)
|
|
||||||
throw new Error('authentication failed')
|
|
||||||
|
|
||||||
const allowedRPCs = await this.getRPCForUser(res[0])
|
|
||||||
const randomPort = 20000 + Math.floor(Math.random() * 10000)
|
|
||||||
while(true){
|
|
||||||
try{
|
|
||||||
let commSock = new RPCServer(randomPort, allowedRPCs, {
|
|
||||||
closeHandler: () => {
|
|
||||||
console.log(res[0].name, 'disconnected')
|
|
||||||
commSock.destroy()
|
|
||||||
},
|
|
||||||
connectionHandler: () => {
|
|
||||||
console.log(res[0].name, 'connected')
|
|
||||||
cancelTimeout()
|
|
||||||
},
|
|
||||||
sesame: tokenValue
|
|
||||||
})
|
|
||||||
const timeout = setTimeout(() => {
|
|
||||||
console.log(res[0].name, 'timeout')
|
|
||||||
commSock.destroy()
|
|
||||||
}, 10000)
|
|
||||||
const cancelTimeout = () => { clearTimeout(timeout) }
|
|
||||||
break;
|
|
||||||
}catch(e){
|
|
||||||
//retry
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
port: randomPort,
|
|
||||||
user: res[0],
|
|
||||||
token: {
|
|
||||||
value: tokenValue,
|
|
||||||
user_id: res[0].id!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
createToken = async(user:User): Promise<Token> => {
|
|
||||||
const old = await this.admin.knex.select('*').from('tokens').where({user_id: user.id})
|
|
||||||
if(old.length === 0){
|
|
||||||
const token:Token = {
|
|
||||||
value: uuid(),
|
|
||||||
user_id: user.id!
|
|
||||||
}
|
|
||||||
await this.admin.knex('tokens').insert(token)
|
|
||||||
return token
|
|
||||||
}else{
|
|
||||||
return old[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { FrontworkAdmin } from './Admin/Admin'
|
import { FrontworkAdmin } from './Admin/Admin'
|
||||||
import { RaidManager } from "./Components/Raid/RaidManager";
|
import { RaidManager } from "./Components/Raid/RaidManager";
|
||||||
import { ItemManager } from "./Components/Item/ItemManager";
|
import { ItemManager } from "./Components/Item/ItemManager";
|
||||||
import { LoginManager } from "./Components/User/UserManager";
|
import { LoginManager } from "./Components/User/LoginManager";
|
||||||
import { Debugger } from './Components/Debugger/Debugger';
|
import { Debugger } from './Components/Debugger/Debugger';
|
||||||
import { FrontworkComponent } from './Types/FrontworkComponent';
|
import { FrontworkComponent } from './Types/FrontworkComponent';
|
||||||
import { GuildManager } from './Components/Guild/GuildManager';
|
import { GuildManager } from './Components/Guild/GuildManager';
|
||||||
@@ -10,13 +10,13 @@ require('events').EventEmitter.defaultMaxListeners = 0;
|
|||||||
let raidManager = new RaidManager()
|
let raidManager = new RaidManager()
|
||||||
let itemManager = new ItemManager()
|
let itemManager = new ItemManager()
|
||||||
let guildManager = new GuildManager()
|
let guildManager = new GuildManager()
|
||||||
let userManager = new LoginManager([
|
let loginManager = new LoginManager([
|
||||||
raidManager,
|
raidManager,
|
||||||
itemManager,
|
itemManager,
|
||||||
guildManager
|
guildManager
|
||||||
])
|
])
|
||||||
|
|
||||||
let components:FrontworkComponent[] = [ guildManager, raidManager, itemManager, userManager ]
|
let components:FrontworkComponent[] = [ guildManager, raidManager, itemManager, loginManager ]
|
||||||
let dbg = new Debugger(components)
|
let dbg = new Debugger(components)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import * as Knex from "knex"
|
import * as Knex from "knex"
|
||||||
import { RPCExporter } from "rpclibrary";
|
import { RPCExporter } from "rpclibrary";
|
||||||
import { RaidManagerFeatureIfc } from "../Components/Raid/RPCInterface";
|
import { RaidManagerFeatureIfc } from "../Components/Raid/RPCInterface";
|
||||||
import { ItemManagerIfc, ItemManagerFeatureIfc } from "../Components/Item/RPCInterface";
|
import { LoginManagerIfc, LoginManagerFeatureIfc } from "../Components/User/RPCInterface";
|
||||||
import { UserManagerIfc, UserManagerFeatureIfc } from "../Components/User/RPCInterface";
|
|
||||||
|
|
||||||
|
|
||||||
export declare type NotificationSeverity = 'Info' | 'Important' | 'Error';
|
export declare type NotificationSeverity = 'Info' | 'Important' | 'Error';
|
||||||
@@ -19,7 +18,7 @@ export type TableDefiniton = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type Rank = "ADMIN" | "Guildmaster" | "Officer" | "Classleader" | "Raider" | "Trial" | "Social" | "Guest"
|
export type Rank = "ADMIN" | "Guildmaster" | "Officer" | "Classleader" | "Raider" | "Trial" | "Social" | "Guest"
|
||||||
export const _Rank : Rank[] = ["Guildmaster" , "Officer" , "Classleader" , "Raider" , "Trial" , "Social" , "Guest"]
|
export const _Rank : Rank[] = ["ADMIN" , "Guildmaster" , "Officer" , "Classleader" , "Raider" , "Trial" , "Social" , "Guest"]
|
||||||
export type Class = "Warrior" | "Rogue" | "Hunter" | "Mage" | "Warlock" | "Priest" | "Shaman" | "Paladin" | "Druid"
|
export type Class = "Warrior" | "Rogue" | "Hunter" | "Mage" | "Warlock" | "Priest" | "Shaman" | "Paladin" | "Druid"
|
||||||
export const _Class : Class[] = ["Warrior" , "Rogue" , "Hunter" , "Mage" , "Warlock" , "Priest" , "Shaman" , "Paladin" , "Druid"]
|
export const _Class : Class[] = ["Warrior" , "Rogue" , "Hunter" , "Mage" , "Warlock" , "Priest" , "Shaman" , "Paladin" , "Druid"]
|
||||||
|
|
||||||
@@ -56,17 +55,17 @@ export type Signup = {
|
|||||||
export type Token = {
|
export type Token = {
|
||||||
value: string
|
value: string
|
||||||
user_id: number
|
user_id: number
|
||||||
created?: number
|
created: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Auth = {port: number, user: User, token: Token}
|
export type Auth = {port: number, user: User, token: Token}
|
||||||
|
|
||||||
export type FrontcraftIfc = UserManagerIfc
|
export type FrontcraftIfc = LoginManagerIfc
|
||||||
& ItemManagerIfc
|
//& ItemManagerIfc
|
||||||
|
|
||||||
export type FrontcraftFeatureIfc = RaidManagerFeatureIfc
|
export type FrontcraftFeatureIfc = RaidManagerFeatureIfc
|
||||||
& UserManagerFeatureIfc
|
& LoginManagerFeatureIfc
|
||||||
& ItemManagerFeatureIfc
|
//& ItemManagerFeatureIfc
|
||||||
|
|
||||||
export type Spec = {
|
export type Spec = {
|
||||||
id?: number,
|
id?: number,
|
||||||
|
|||||||
Generated
+6
-6
@@ -14269,9 +14269,9 @@
|
|||||||
"integrity": "sha512-ZYzRkETgBrdEGzL5JSKimvjI2CX7ioyZCkX2BpcfyjqI+079W0wHAyj5W4rIZMcDSOHgLZtgz1IdDi/vU77KEQ=="
|
"integrity": "sha512-ZYzRkETgBrdEGzL5JSKimvjI2CX7ioyZCkX2BpcfyjqI+079W0wHAyj5W4rIZMcDSOHgLZtgz1IdDi/vU77KEQ=="
|
||||||
},
|
},
|
||||||
"rpclibrary": {
|
"rpclibrary": {
|
||||||
"version": "1.4.2",
|
"version": "1.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/rpclibrary/-/rpclibrary-1.5.1.tgz",
|
||||||
"integrity": "sha512-IFigD+65a9MM+1AgEH5nurUzCyMg9hawqtnOA67/PtTGP5GsnWxaFESKl03k8L/PQ8ptZkWcub/63bfxkrwyMw==",
|
"integrity": "sha512-EN6wlifkFmEQrHhtbalS0i90ZBNbLNFcrQ8hTrcJLBuNMFab49R8i5fruoDLDJM88iPcx6eWccI6zLHK7Qkl2A==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"bsock": "^0.1.9",
|
"bsock": "^0.1.9",
|
||||||
"http": "0.0.0",
|
"http": "0.0.0",
|
||||||
@@ -14279,9 +14279,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"uuid": {
|
"uuid": {
|
||||||
"version": "3.3.3",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||||
"integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ=="
|
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -69,7 +69,7 @@
|
|||||||
"normalize.css": "6.0.0",
|
"normalize.css": "6.0.0",
|
||||||
"pace-js": "1.0.2",
|
"pace-js": "1.0.2",
|
||||||
"roboto-fontface": "0.8.0",
|
"roboto-fontface": "0.8.0",
|
||||||
"rpclibrary": "^1.4.2",
|
"rpclibrary": "^1.5.1",
|
||||||
"rxjs": "6.5.2",
|
"rxjs": "6.5.2",
|
||||||
"rxjs-compat": "6.3.0",
|
"rxjs-compat": "6.3.0",
|
||||||
"socicon": "3.0.5",
|
"socicon": "3.0.5",
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import { Component } from '@angular/core';
|
|||||||
selector: 'ngx-footer',
|
selector: 'ngx-footer',
|
||||||
styleUrls: ['./footer.component.scss'],
|
styleUrls: ['./footer.component.scss'],
|
||||||
template: `
|
template: `
|
||||||
<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>
|
<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>
|
||||||
<div class="socials">
|
<div class="socials">
|
||||||
<a href="http://www.versioncontrol.me/" target="_blank" class="ion ion-social-github"></a>
|
<a href="https://gitea.nitowa.xyz/" target="_blank" class="ion ion-social-github"></a>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -10,10 +10,7 @@
|
|||||||
<div class="header-container">
|
<div class="header-container">
|
||||||
<nb-actions size="small">
|
<nb-actions size="small">
|
||||||
|
|
||||||
<nb-action class="control-item">
|
<nb-action class="control-item" icon="message-square-outline"></nb-action>
|
||||||
<nb-search type="rotate-layout"></nb-search>
|
|
||||||
</nb-action>
|
|
||||||
<nb-action class="control-item" icon="email-outline"></nb-action>
|
|
||||||
<nb-action class="control-item" icon="bell-outline"></nb-action>
|
<nb-action class="control-item" icon="bell-outline"></nb-action>
|
||||||
|
|
||||||
<nb-action class="user-action">
|
<nb-action class="user-action">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { NbMediaBreakpointsService, NbMenuService, NbSidebarService, NbThemeService } from '@nebular/theme';
|
import { NbMediaBreakpointsService, NbMenuService, NbSidebarService, NbThemeService, NbContextMenuComponent, NbMenuItem } from '@nebular/theme';
|
||||||
|
|
||||||
import { LayoutService } from '../../../@core/utils';
|
import { LayoutService } from '../../../@core/utils';
|
||||||
import { map, takeUntil } from 'rxjs/operators';
|
import { map, takeUntil } from 'rxjs/operators';
|
||||||
@@ -39,14 +39,14 @@ export class HeaderComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
currentTheme = 'dark';
|
currentTheme = 'dark';
|
||||||
|
|
||||||
userMenu = [ { title: 'Profile' }, { title: 'Log out' } ];
|
userMenu : NbMenuItem[] = [ { title: 'Profile' }, { title: 'Log out', url: '/auth/logout' } ];
|
||||||
|
|
||||||
constructor(private sidebarService: NbSidebarService,
|
constructor(private sidebarService: NbSidebarService,
|
||||||
private menuService: NbMenuService,
|
private menuService: NbMenuService,
|
||||||
private themeService: NbThemeService,
|
private themeService: NbThemeService,
|
||||||
private layoutService: LayoutService,
|
private layoutService: LayoutService,
|
||||||
private breakpointService: NbMediaBreakpointsService,
|
private breakpointService: NbMediaBreakpointsService,
|
||||||
private loginService: LoginApiService
|
private loginService: LoginApiService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@@ -92,6 +92,10 @@ export class HeaderComponent implements OnInit, OnDestroy {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logout() {
|
||||||
|
this.loginService.logout()
|
||||||
|
}
|
||||||
|
|
||||||
navigateHome() {
|
navigateHome() {
|
||||||
this.menuService.navigateHome();
|
this.menuService.navigateHome();
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
export * from './one-column/one-column.layout';
|
export * from './one-column/one-column.layout';
|
||||||
export * from './two-columns/two-columns.layout';
|
export * from './two-columns/two-columns.layout';
|
||||||
export * from './three-columns/three-columns.layout';
|
export * from './three-columns/three-columns.layout';
|
||||||
|
export * from './one-column-no-sidebar/one-column.layout';
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
@import '../../styles/themes';
|
||||||
|
@import '~bootstrap/scss/mixins/breakpoints';
|
||||||
|
@import '~@nebular/theme/styles/global/breakpoints';
|
||||||
|
|
||||||
|
@include nb-install-component() {
|
||||||
|
.menu-sidebar ::ng-deep .scrollable {
|
||||||
|
padding-top: nb-theme(layout-padding-top);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ngx-one-column-no-sidebar-layout',
|
||||||
|
styleUrls: ['./one-column.layout.scss'],
|
||||||
|
template: `
|
||||||
|
<nb-layout windowMode>
|
||||||
|
|
||||||
|
<nb-layout-column>
|
||||||
|
<ng-content select="router-outlet"></ng-content>
|
||||||
|
</nb-layout-column>
|
||||||
|
|
||||||
|
<nb-layout-footer fixed>
|
||||||
|
<ngx-footer></ngx-footer>
|
||||||
|
</nb-layout-footer>
|
||||||
|
</nb-layout>
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
export class OneColumnNoSidebarLayoutComponent {}
|
||||||
@@ -33,6 +33,7 @@ import {
|
|||||||
OneColumnLayoutComponent,
|
OneColumnLayoutComponent,
|
||||||
ThreeColumnsLayoutComponent,
|
ThreeColumnsLayoutComponent,
|
||||||
TwoColumnsLayoutComponent,
|
TwoColumnsLayoutComponent,
|
||||||
|
OneColumnNoSidebarLayoutComponent,
|
||||||
} from './layouts';
|
} from './layouts';
|
||||||
import { DEFAULT_THEME } from './styles/theme.default';
|
import { DEFAULT_THEME } from './styles/theme.default';
|
||||||
import { COSMIC_THEME } from './styles/theme.cosmic';
|
import { COSMIC_THEME } from './styles/theme.cosmic';
|
||||||
@@ -61,6 +62,7 @@ const COMPONENTS = [
|
|||||||
OneColumnLayoutComponent,
|
OneColumnLayoutComponent,
|
||||||
ThreeColumnsLayoutComponent,
|
ThreeColumnsLayoutComponent,
|
||||||
TwoColumnsLayoutComponent,
|
TwoColumnsLayoutComponent,
|
||||||
|
OneColumnNoSidebarLayoutComponent
|
||||||
];
|
];
|
||||||
const PIPES = [
|
const PIPES = [
|
||||||
CapitalizePipe,
|
CapitalizePipe,
|
||||||
|
|||||||
@@ -2,11 +2,6 @@ import { ExtraOptions, RouterModule, Routes } from '@angular/router';
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
|
||||||
path: 'pages',
|
|
||||||
loadChildren: () => import('./demo_pages/pages.module')
|
|
||||||
.then(m => m.PagesModule),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: 'auth',
|
path: 'auth',
|
||||||
loadChildren: () => import('./frontcraft/auth/auth.module')
|
loadChildren: () => import('./frontcraft/auth/auth.module')
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import {
|
|||||||
NbToastrModule,
|
NbToastrModule,
|
||||||
NbWindowModule,
|
NbWindowModule,
|
||||||
} from '@nebular/theme';
|
} from '@nebular/theme';
|
||||||
|
import { LoginApiService } from './frontcraft/services/login-api';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [AppComponent],
|
declarations: [AppComponent],
|
||||||
@@ -28,9 +29,7 @@ import {
|
|||||||
BrowserAnimationsModule,
|
BrowserAnimationsModule,
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
AppRoutingModule,
|
AppRoutingModule,
|
||||||
|
|
||||||
ThemeModule.forRoot(),
|
ThemeModule.forRoot(),
|
||||||
|
|
||||||
NbSidebarModule.forRoot(),
|
NbSidebarModule.forRoot(),
|
||||||
NbMenuModule.forRoot(),
|
NbMenuModule.forRoot(),
|
||||||
NbDatepickerModule.forRoot(),
|
NbDatepickerModule.forRoot(),
|
||||||
@@ -43,6 +42,9 @@ import {
|
|||||||
CoreModule.forRoot(),
|
CoreModule.forRoot(),
|
||||||
],
|
],
|
||||||
bootstrap: [AppComponent],
|
bootstrap: [AppComponent],
|
||||||
|
providers: [
|
||||||
|
|
||||||
|
]
|
||||||
})
|
})
|
||||||
export class AppModule {
|
export class AppModule {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { NbMenuItem } from '@nebular/theme';
|
import { NbMenuItem } from '@nebular/theme';
|
||||||
|
|
||||||
export const MENU_ITEMS: NbMenuItem[] = [
|
export const MENU_ITEMS: NbMenuItem[] = [];
|
||||||
];
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { NgModule } from '@angular/core';
|
|||||||
|
|
||||||
import { PagesComponent } from './pages.component';
|
import { PagesComponent } from './pages.component';
|
||||||
import { NotFoundComponent } from './miscellaneous/not-found/not-found.component';
|
import { NotFoundComponent } from './miscellaneous/not-found/not-found.component';
|
||||||
|
import { AuthComponent } from '../frontcraft/auth/auth-layout.component';
|
||||||
|
|
||||||
const routes: Routes = [{
|
const routes: Routes = [{
|
||||||
path: '',
|
path: '',
|
||||||
|
|||||||
@@ -1,13 +1,22 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { LoginApiService } from '../services/login-api';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'auth-layout',
|
selector: 'auth-layout',
|
||||||
template: `
|
template: `
|
||||||
<ngx-one-column-layout>
|
<ngx-one-column-no-sidebar-layout>
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
</ngx-one-column-layout>
|
</ngx-one-column-no-sidebar-layout>
|
||||||
`,
|
`,
|
||||||
})
|
})
|
||||||
export class AuthComponent {
|
|
||||||
|
export class AuthComponent implements OnInit{
|
||||||
|
constructor(
|
||||||
|
private loginSvc : LoginApiService,
|
||||||
|
private router: Router
|
||||||
|
){}
|
||||||
|
|
||||||
|
ngOnInit(){
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,22 @@ import { NgModule } from '@angular/core';
|
|||||||
import { RouterModule, Routes } from '@angular/router';
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
import { MyLoginComponent } from './login/login.component';
|
import { MyLoginComponent } from './login/login.component';
|
||||||
import { AuthComponent } from './auth-layout.component';
|
import { AuthComponent } from './auth-layout.component';
|
||||||
|
import { LogoutComponent } from './logout/logout.component';
|
||||||
|
import { RegisterComponent } from './register/register.component';
|
||||||
|
|
||||||
export const routes: Routes = [
|
export const routes: Routes = [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
component: AuthComponent,
|
component: AuthComponent,
|
||||||
children: [
|
children: [
|
||||||
|
{
|
||||||
|
path: 'register',
|
||||||
|
component: RegisterComponent
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'logout',
|
||||||
|
component: LogoutComponent,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '**',
|
path: '**',
|
||||||
component: MyLoginComponent,
|
component: MyLoginComponent,
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ import {
|
|||||||
NbButtonModule,
|
NbButtonModule,
|
||||||
NbCheckboxModule,
|
NbCheckboxModule,
|
||||||
NbInputModule,
|
NbInputModule,
|
||||||
NbMenuModule
|
NbMenuModule,
|
||||||
|
NbCardModule,
|
||||||
|
NbSelectModule
|
||||||
} from '@nebular/theme';
|
} from '@nebular/theme';
|
||||||
import { MyAuthRoutingModule } from './auth-routing.module';
|
import { MyAuthRoutingModule } from './auth-routing.module';
|
||||||
import { MyLoginComponent } from './login/login.component';
|
import { MyLoginComponent } from './login/login.component';
|
||||||
@@ -17,6 +19,8 @@ import { ThemeModule } from '../../@theme/theme.module';
|
|||||||
import { DashboardModule } from '../../demo_pages/dashboard/dashboard.module';
|
import { DashboardModule } from '../../demo_pages/dashboard/dashboard.module';
|
||||||
import { ECommerceModule } from '../../demo_pages/e-commerce/e-commerce.module';
|
import { ECommerceModule } from '../../demo_pages/e-commerce/e-commerce.module';
|
||||||
import { MiscellaneousModule } from '../../demo_pages/miscellaneous/miscellaneous.module';
|
import { MiscellaneousModule } from '../../demo_pages/miscellaneous/miscellaneous.module';
|
||||||
|
import { LogoutComponent } from './logout/logout.component';
|
||||||
|
import { RegisterComponent } from './register/register.component';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
@@ -34,9 +38,12 @@ import { MiscellaneousModule } from '../../demo_pages/miscellaneous/miscellaneou
|
|||||||
DashboardModule,
|
DashboardModule,
|
||||||
ECommerceModule,
|
ECommerceModule,
|
||||||
MiscellaneousModule,
|
MiscellaneousModule,
|
||||||
|
NbCardModule,
|
||||||
|
NbSelectModule
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
|
RegisterComponent,
|
||||||
|
LogoutComponent,
|
||||||
AuthComponent,
|
AuthComponent,
|
||||||
MyLoginComponent
|
MyLoginComponent
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,19 +1,4 @@
|
|||||||
<h1 id="title" class="title">Login</h1>
|
<h1 id="title" class="title">Login</h1>
|
||||||
<p class="sub-title">Hello! Log in with your email.</p>
|
|
||||||
|
|
||||||
<nb-alert *ngIf="showMessages.error && errors?.length && !submitted" outline="danger" role="alert">
|
|
||||||
<p class="alert-title"><b>Oh snap!</b></p>
|
|
||||||
<ul class="alert-message-list">
|
|
||||||
<li *ngFor="let error of errors" class="alert-message">{{ error }}</li>
|
|
||||||
</ul>
|
|
||||||
</nb-alert>
|
|
||||||
|
|
||||||
<nb-alert *ngIf="showMessages.success && messages?.length && !submitted" outline="success" role="alert">
|
|
||||||
<p class="alert-title"><b>Hooray!</b></p>
|
|
||||||
<ul class="alert-message-list">
|
|
||||||
<li *ngFor="let message of messages" class="alert-message">{{ message }}</li>
|
|
||||||
</ul>
|
|
||||||
</nb-alert>
|
|
||||||
|
|
||||||
<form (ngSubmit)="login()" #form="ngForm" aria-labelledby="title">
|
<form (ngSubmit)="login()" #form="ngForm" aria-labelledby="title">
|
||||||
|
|
||||||
@@ -21,25 +6,16 @@
|
|||||||
<label class="label" for="input-email">Email address:</label>
|
<label class="label" for="input-email">Email address:</label>
|
||||||
<input nbInput
|
<input nbInput
|
||||||
fullWidth
|
fullWidth
|
||||||
[(ngModel)]="user.email"
|
[(ngModel)]="user.name"
|
||||||
#email="ngModel"
|
#email="ngModel"
|
||||||
name="email"
|
name="name"
|
||||||
id="input-email"
|
id="input-email"
|
||||||
pattern=".+@.+\..+"
|
pattern=".+"
|
||||||
placeholder="Email address"
|
placeholder="Username"
|
||||||
fieldSize="giant"
|
fieldSize="giant"
|
||||||
autofocus
|
autofocus
|
||||||
[status]="email.dirty ? (email.invalid ? 'danger' : 'success') : ''"
|
[required]="true">
|
||||||
[required]="true"
|
|
||||||
[attr.aria-invalid]="email.invalid && email.touched ? true : null">
|
|
||||||
<ng-container *ngIf="email.invalid && email.touched">
|
|
||||||
<p class="error-message" *ngIf="email.errors?.required">
|
|
||||||
Email is required!
|
|
||||||
</p>
|
|
||||||
<p class="error-message" *ngIf="email.errors?.pattern">
|
|
||||||
Email should be the real one!
|
|
||||||
</p>
|
|
||||||
</ng-container>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-control-group">
|
<div class="form-control-group">
|
||||||
@@ -55,20 +31,9 @@
|
|||||||
fieldSize="giant"
|
fieldSize="giant"
|
||||||
[status]="password.dirty ? (password.invalid ? 'danger' : 'success') : ''"
|
[status]="password.dirty ? (password.invalid ? 'danger' : 'success') : ''"
|
||||||
[required]="true"
|
[required]="true"
|
||||||
[minlength]="6"
|
[minlength]="1"
|
||||||
[maxlength]="15"
|
[maxlength]="15"
|
||||||
[attr.aria-invalid]="password.invalid && password.touched ? true : null">
|
[attr.aria-invalid]="password.invalid && password.touched ? true : null">
|
||||||
<ng-container *ngIf="password.invalid && password.touched ">
|
|
||||||
<p class="error-message" *ngIf="password.errors?.required">
|
|
||||||
Password is required!
|
|
||||||
</p>
|
|
||||||
<p class="error-message" *ngIf="password.errors?.minlength || password.errors?.maxlength">
|
|
||||||
Password should contains
|
|
||||||
from {{ 6 }}
|
|
||||||
to {{ 15 }}
|
|
||||||
characters
|
|
||||||
</p>
|
|
||||||
</ng-container>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-control-group accept-group">
|
<div class="form-control-group accept-group">
|
||||||
@@ -88,5 +53,5 @@
|
|||||||
|
|
||||||
|
|
||||||
<section class="another-action" aria-label="Register">
|
<section class="another-action" aria-label="Register">
|
||||||
Don't have an account? <a class="text-link" routerLink="../register">Register</a>
|
Don't have an account? <a class="text-link" routerLink="/auth/register">Register</a>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -25,7 +25,14 @@ export class MyLoginComponent implements OnInit{
|
|||||||
){}
|
){}
|
||||||
|
|
||||||
ngOnInit(){
|
ngOnInit(){
|
||||||
console.log(this.router)
|
this.loginApi.checkLogin().then(loggedin => {
|
||||||
|
if(loggedin){
|
||||||
|
this.router.navigateByUrl("/")
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
login(){
|
||||||
|
this.loginApi.login(this.user.name, this.user.password)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
You will be redirected shortly. If not click here <a href="/auth/login">click</a>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { LoginApiService } from '../../services/login-api';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'mylogout',
|
||||||
|
templateUrl: './logout.component.html',
|
||||||
|
})
|
||||||
|
export class LogoutComponent implements OnInit{
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private loginApi : LoginApiService
|
||||||
|
){}
|
||||||
|
|
||||||
|
ngOnInit(){
|
||||||
|
this.loginApi.logout()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
<h1 id="title" class="title">Account application</h1>
|
||||||
|
|
||||||
|
<form (ngSubmit)="register()" #form="ngForm" aria-labelledby="title">
|
||||||
|
|
||||||
|
<div class="form-control-group">
|
||||||
|
<label class="label" for="input-email">Email address:</label>
|
||||||
|
<input nbInput
|
||||||
|
fullWidth
|
||||||
|
[(ngModel)]="user.email"
|
||||||
|
#email="ngModel"
|
||||||
|
name="name"
|
||||||
|
id="input-email"
|
||||||
|
pattern=".+"
|
||||||
|
placeholder="Email Address"
|
||||||
|
fieldSize="giant"
|
||||||
|
autofocus
|
||||||
|
[required]="true">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-control-group">
|
||||||
|
<label class="label" for="input-username">Username:</label>
|
||||||
|
<input nbInput
|
||||||
|
fullWidth
|
||||||
|
[(ngModel)]="user.name"
|
||||||
|
#email="ngModel"
|
||||||
|
name="name"
|
||||||
|
id="input-username"
|
||||||
|
pattern=".+"
|
||||||
|
placeholder="Username"
|
||||||
|
fieldSize="giant"
|
||||||
|
autofocus
|
||||||
|
[required]="true">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-control-group">
|
||||||
|
<label class="label" for="input-password">Password:</label>
|
||||||
|
<input nbInput
|
||||||
|
fullWidth
|
||||||
|
[(ngModel)]="user.password"
|
||||||
|
#password="ngModel"
|
||||||
|
name="password"
|
||||||
|
type="password"
|
||||||
|
id="input-password"
|
||||||
|
placeholder="Password"
|
||||||
|
fieldSize="giant"
|
||||||
|
[status]="password.dirty ? (password.invalid ? 'danger' : 'success') : ''"
|
||||||
|
[required]="true"
|
||||||
|
[minlength]="1"
|
||||||
|
[maxlength]="15"
|
||||||
|
[attr.aria-invalid]="password.invalid && password.touched ? true : null">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-control-group accept-group">
|
||||||
|
<nb-checkbox name="rememberMe" [(ngModel)]="user.rememberMe" *ngIf="rememberMe">Remember me</nb-checkbox>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nb-card>
|
||||||
|
<nb-card-body>
|
||||||
|
<nb-checkbox [(ngModel)]="showApplication" name="amMember" #checkbox>I am already a member</nb-checkbox>
|
||||||
|
<br />
|
||||||
|
<span *ngIf="showApplication">
|
||||||
|
And my main is <input name="preMember" nbInput> with rank <nb-select placeholder="Rank">
|
||||||
|
<nb-option *ngFor="let rank of ranks" [value]=rank >{{rank}}</nb-option>
|
||||||
|
|
||||||
|
</nb-select>
|
||||||
|
</span>
|
||||||
|
<span *ngIf="!showApplication">Hello my name is <input name="charName" nbInput>
|
||||||
|
I am playing a level 60 <input name="charName" placeholder="Spec + Class" nbInput> and I would like to join tranquil because
|
||||||
|
<textarea nbInput fullWidth placeholder="reason" style="min-height: 400px"></textarea>
|
||||||
|
|
||||||
|
</span>
|
||||||
|
|
||||||
|
</nb-card-body>
|
||||||
|
</nb-card>
|
||||||
|
|
||||||
|
<button nbButton
|
||||||
|
fullWidth
|
||||||
|
status="primary"
|
||||||
|
size="giant"
|
||||||
|
[disabled]="submitted || !form.valid"
|
||||||
|
[class.btn-pulse]="submitted">
|
||||||
|
Log In
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
<section class="another-action" aria-label="Register">
|
||||||
|
Back to <a class="text-link" routerLink="auth/login">Login</a>
|
||||||
|
</section>
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { LoginApiService } from '../../services/login-api';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { _Rank } from '../../../../../../backend/Types/Types'
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'register',
|
||||||
|
templateUrl: './register.component.html',
|
||||||
|
})
|
||||||
|
export class RegisterComponent implements OnInit{
|
||||||
|
|
||||||
|
user: any = {};
|
||||||
|
showApplication = false
|
||||||
|
ranks = _Rank
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private router : Router,
|
||||||
|
private loginApi : LoginApiService
|
||||||
|
){}
|
||||||
|
|
||||||
|
ngOnInit(){
|
||||||
|
this.loginApi.checkLogin().then(loggedin => {
|
||||||
|
if(loggedin){
|
||||||
|
this.router.navigateByUrl("/")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
login(){
|
||||||
|
this.loginApi.login(this.user.name, this.user.password)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, AfterContentChecked, OnInit } from '@angular/core';
|
||||||
import { NbMenuItem } from '@nebular/theme';
|
import { NbMenuItem } from '@nebular/theme';
|
||||||
|
import { LoginApiService } from '../services/login-api';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'auth-layout',
|
selector: 'page-layout',
|
||||||
template: `
|
template: `
|
||||||
|
|
||||||
<ngx-one-column-layout>
|
<ngx-one-column-layout>
|
||||||
@@ -12,12 +14,25 @@ import { NbMenuItem } from '@nebular/theme';
|
|||||||
</ngx-one-column-layout>
|
</ngx-one-column-layout>
|
||||||
`,
|
`,
|
||||||
})
|
})
|
||||||
export class PagesLayoutComponent {
|
export class PagesLayoutComponent implements OnInit{
|
||||||
menu:NbMenuItem[] = [{
|
menu:NbMenuItem[] = [{
|
||||||
icon: 'cube-outline',
|
icon: 'people-outline',
|
||||||
title: 'test'
|
title: 'People'
|
||||||
},{
|
},{
|
||||||
icon: 'globe-2-outline',
|
icon: 'clock-outline',
|
||||||
title: 'test2'
|
title: 'Raids'
|
||||||
}]
|
}]
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private loginSvc : LoginApiService,
|
||||||
|
private router : Router
|
||||||
|
){}
|
||||||
|
|
||||||
|
ngOnInit() : void {
|
||||||
|
this.loginSvc.checkLogin().then(loggedin => {
|
||||||
|
if(!loggedin){
|
||||||
|
this.router.navigateByUrl("/auth")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,8 @@ import {
|
|||||||
NbButtonModule,
|
NbButtonModule,
|
||||||
NbCheckboxModule,
|
NbCheckboxModule,
|
||||||
NbInputModule,
|
NbInputModule,
|
||||||
NbMenuModule
|
NbMenuModule,
|
||||||
|
NbCardModule
|
||||||
} from '@nebular/theme';
|
} from '@nebular/theme';
|
||||||
import { MyAuthRoutingModule } from './pages-routing.module';
|
import { MyAuthRoutingModule } from './pages-routing.module';
|
||||||
import { FrontcraftDashboardComponent } from './dashboard/dashboard.component';
|
import { FrontcraftDashboardComponent } from './dashboard/dashboard.component';
|
||||||
@@ -34,7 +35,8 @@ import { MiscellaneousModule } from '../../demo_pages/miscellaneous/miscellaneou
|
|||||||
DashboardModule,
|
DashboardModule,
|
||||||
ECommerceModule,
|
ECommerceModule,
|
||||||
MiscellaneousModule,
|
MiscellaneousModule,
|
||||||
|
NbCardModule,
|
||||||
|
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
PagesLayoutComponent,
|
PagesLayoutComponent,
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
import { Injectable } from "@angular/core";
|
import { Injectable, Injector, NgZone } from "@angular/core";
|
||||||
import {RPCSocket} from 'rpclibrary/js/src/Frontend'
|
import {RPCSocket} from 'rpclibrary/js/src/Frontend'
|
||||||
|
|
||||||
import { Token, Auth, User, _Class, FrontcraftFeatureIfc, SomeOf, FrontcraftIfc, } from '../../../../../backend/Types/Types'
|
import { Token, Auth, User, _Class, FrontcraftFeatureIfc, SomeOf, FrontcraftIfc, } from '../../../../../backend/Types/Types'
|
||||||
import { CookieService } from 'ngx-cookie-service';
|
import { CookieService } from 'ngx-cookie-service';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class LoginApiService{
|
export class LoginApiService{
|
||||||
@@ -11,93 +12,112 @@ export class LoginApiService{
|
|||||||
private privSocket: RPCSocket & SomeOf<FrontcraftFeatureIfc>
|
private privSocket: RPCSocket & SomeOf<FrontcraftFeatureIfc>
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private cookieSvc : CookieService
|
private injector: Injector,
|
||||||
|
private cookieSvc : CookieService,
|
||||||
|
private ngZone : NgZone
|
||||||
){}
|
){}
|
||||||
|
|
||||||
getUnprivilegedSocket = () : RPCSocket & FrontcraftIfc => this.socket
|
getUnprivilegedSocket = () : RPCSocket & FrontcraftIfc => this.socket
|
||||||
|
|
||||||
private getPrivilegedSocket = async (auth:Auth) : Promise<RPCSocket & SomeOf<FrontcraftFeatureIfc>> => {
|
private getPrivilegedSocket = async (auth:Auth) : Promise<RPCSocket & SomeOf<FrontcraftFeatureIfc>> => {
|
||||||
if(this.privSocket) return this.privSocket
|
if(this.privSocket) return this.privSocket
|
||||||
if(auth.user.rank === 'Guest'){
|
if(auth == null) throw new Error("Bad Auth")
|
||||||
return await RPCSocket.makeSocket<SomeOf<FrontcraftFeatureIfc>>(
|
|
||||||
20001,
|
try{
|
||||||
|
const sock = new RPCSocket(
|
||||||
|
auth.port,
|
||||||
window.location.hostname
|
window.location.hostname
|
||||||
)
|
)
|
||||||
}
|
|
||||||
try{
|
const authSock = await sock.connect<RPCSocket & SomeOf<FrontcraftFeatureIfc>>(auth.token.value)
|
||||||
const sock = await RPCSocket.makeSocket<SomeOf<FrontcraftFeatureIfc>>(
|
|
||||||
auth.port,
|
sock.hook('kick', () => this.logout())
|
||||||
window.location.hostname,
|
sock.hook('getUserData', () => auth)
|
||||||
auth.token.value
|
sock.hook('navigate', (where:string) => {
|
||||||
)
|
this.ngZone.run(() => {
|
||||||
|
this.injector.get(Router).navigateByUrl(where);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
sock.on('error', (e) => {
|
||||||
|
console.log('Socket error', e)
|
||||||
|
this.logout()
|
||||||
|
})
|
||||||
|
|
||||||
//login success
|
|
||||||
this.auth = auth
|
this.auth = auth
|
||||||
this.privSocket = sock
|
this.privSocket = authSock
|
||||||
this.setCookie(auth.token)
|
this.cookieSvc.set('token', JSON.stringify(auth))
|
||||||
return sock
|
return authSock
|
||||||
}catch(e){
|
}catch(e){
|
||||||
//login failed
|
//login failed
|
||||||
throw new Error('login failed')
|
throw new Error(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getFeature = async <K extends keyof FrontcraftFeatureIfc>(feature : K) : Promise<void | FrontcraftFeatureIfc[K]> => {
|
getFeature = async <K extends keyof FrontcraftFeatureIfc>(feature : K) : Promise<void | FrontcraftFeatureIfc[K]> => {
|
||||||
const sock = await this.getPrivilegedSocket(this.auth)
|
try{
|
||||||
if(sock[feature]) return <FrontcraftFeatureIfc[K]> sock[feature]
|
const sock = await this.getPrivilegedSocket(this.auth)
|
||||||
|
if(sock[feature]) return <FrontcraftFeatureIfc[K]> sock[feature]
|
||||||
|
}catch(e){
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentUser = () : User => this.auth
|
getCurrentUser = () : User | undefined => this.auth?this.auth.user:undefined
|
||||||
? this.auth.user
|
|
||||||
: {
|
|
||||||
name: 'Guest',
|
|
||||||
specid: 1,
|
|
||||||
pwhash: '',
|
|
||||||
rank: 'Guest'
|
|
||||||
}
|
|
||||||
|
|
||||||
authenticate = async (token : Token | string) : Promise<RPCSocket & SomeOf<FrontcraftFeatureIfc>> => {
|
login = async (username: string, password: string) : Promise<RPCSocket & SomeOf<FrontcraftFeatureIfc>> => {
|
||||||
const auth = await this.socket.Authenticator.authenticate(token)
|
|
||||||
return await this.getPrivilegedSocket(auth)
|
|
||||||
}
|
|
||||||
|
|
||||||
login = async (username: string, password: string) => {
|
|
||||||
const buf = str2arraybuf(password)
|
const buf = str2arraybuf(password)
|
||||||
const pwHash = await crypto.subtle.digest('SHA-256', buf);
|
const pwHash = await crypto.subtle.digest('SHA-256', buf);
|
||||||
const token = await this.socket.Authenticator.login(username, buf2hex(pwHash))
|
|
||||||
return await this.authenticate(token)
|
const auth = await this.socket.Authenticator.login(username, buf2hex(pwHash))
|
||||||
|
|
||||||
|
|
||||||
|
if(!auth){
|
||||||
|
await this.logout()
|
||||||
|
throw new Error("Login failed")
|
||||||
|
}
|
||||||
|
const sock = await this.getPrivilegedSocket(auth)
|
||||||
|
return sock
|
||||||
}
|
}
|
||||||
|
|
||||||
logout = () => {
|
logout = async () => {
|
||||||
this.cookieSvc.deleteAll()
|
this.cookieSvc.set('token', undefined)
|
||||||
this.auth = null
|
if(this.auth) await this.socket.Authenticator.logout(this.auth.user.name, this.auth.token.value)
|
||||||
if(this.privSocket) this.privSocket.destroy()
|
if(this.privSocket) this.privSocket.destroy()
|
||||||
this.privSocket = null
|
this.privSocket = null
|
||||||
|
this.auth = null
|
||||||
|
this.ngZone.run(() => {
|
||||||
|
this.injector.get(Router).navigate(['/auth']);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private setCookie = (token: string | Token) => {
|
|
||||||
token = 'string' === typeof token? token : token.value
|
|
||||||
this.cookieSvc.set('token', token)
|
|
||||||
}
|
|
||||||
|
|
||||||
private getCookie = () : string | Token | undefined => {
|
initialize = async () : Promise<any> => {
|
||||||
return this.cookieSvc.get('token')
|
|
||||||
}
|
|
||||||
|
|
||||||
initialize = async () : Promise<RPCSocket> => {
|
|
||||||
const sock = await RPCSocket.makeSocket<FrontcraftIfc>(20000, window.location.hostname)
|
const sock = await RPCSocket.makeSocket<FrontcraftIfc>(20000, window.location.hostname)
|
||||||
this.socket = sock
|
this.socket = sock
|
||||||
|
try{
|
||||||
const cookie = this.getCookie()
|
const cookie = JSON.parse(this.cookieSvc.get('token'))
|
||||||
if(cookie) {
|
if(cookie != null) {
|
||||||
try{
|
try{
|
||||||
return await this.authenticate(cookie)
|
const auth = await sock.Authenticator.getAuth(cookie.token.value)
|
||||||
}catch(e){
|
if(!auth) return sock
|
||||||
this.logout()
|
return await this.getPrivilegedSocket(auth)
|
||||||
|
}catch(e){
|
||||||
|
await this.logout()
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}catch(e){
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return sock
|
getAuth = () => this.auth
|
||||||
|
|
||||||
|
async checkLogin() : Promise<boolean>{
|
||||||
|
if(!this.auth) return false
|
||||||
|
const valid = await this.socket.Authenticator.checkToken(this.auth.token.value, this.auth.user.rank)
|
||||||
|
if(valid) return true
|
||||||
|
await this.logout()
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user