diff --git a/config/texts.example.ts b/config/texts.example.ts
index dad6441..ea8c3dd 100644
--- a/config/texts.example.ts
+++ b/config/texts.example.ts
@@ -9,6 +9,6 @@ export default {
Please do be aware of the fact that this is still very much in development and a lot of stuff will be improved with time.
- Register / Login
+ Login
`,
}
diff --git a/src/classes/extension.ts b/src/classes/extension.ts
index 3273ecb..01ca103 100644
--- a/src/classes/extension.ts
+++ b/src/classes/extension.ts
@@ -154,13 +154,16 @@ export abstract class ExtensionBase implements Extension {
key,
value, {
secure: true,
- httpOnly: true
+ httpOnly: true,
+ path: '/'
}
)
else
return cookie.serialize(
key,
- value
+ value, {
+ path: '/'
+ }
)
}
diff --git a/src/extensions/invite/index.html b/src/extensions/invite/index.html
index 017474f..5f87456 100644
--- a/src/extensions/invite/index.html
+++ b/src/extensions/invite/index.html
@@ -10,7 +10,7 @@
ID
- Link
+ Code
Created at
Used
@@ -19,7 +19,7 @@
{% for link in invite_links %}
{{link.id}}
- {{link.link}}
+ {{link.code}}
{{link.created_at}}
{{"Yes" if link.used else "No"}}
diff --git a/src/extensions/invite/index.ts b/src/extensions/invite/index.ts
index ba576d3..ab4b9ca 100644
--- a/src/extensions/invite/index.ts
+++ b/src/extensions/invite/index.ts
@@ -1,23 +1,41 @@
+import crypto from 'crypto'
import { ExtensionBase, Knex } from '../../modules.ts'
import { unpack } from '../../util.ts'
+import minecraft from '../minecraft/index.ts'
export default class extends ExtensionBase {
override name = 'invite'
override title = 'Invite'
override tables = true
- override admin_only = true
- invite_URL = 'http://127.0.0.1:8000/invite/register/'
+ salt: string
+
+ override init = (context: InitContext) => {
+ this.salt = context.modules.config.salt
+ return ExtensionBase.init(this, context)
+ }
+
+ override requires_admin: Extension['requires_admin'] = (path) => {
+ if (['register', 'create_acc'].includes(path.at(0)??'')) {
+ return false
+ }
+ return true
+ }
+ override requires_login: Extension['requires_login'] = (path) => {
+ if (['register', 'create_acc'].includes(path.at(0)??'')) {
+ return false
+ }
+ return true
+ }
override handle: Extension['handle'] = async (ctx) => {
let [knex]: [Knex] = this.get_dependencies('Knex')
- var location = ctx.path.shift()
+ let location = ctx.path.shift()
switch (location) {
case '':
case undefined:{
-
- var [invite_links, err] = await knex
+ let [invite_links, err] = await knex
.query('_invite')
.select('*')
.then(unpack)
@@ -25,28 +43,121 @@ export default class extends ExtensionBase {
ctx.context.invite_links = invite_links
return this.return_html(ctx, 'index')
}
- case 'create':
+ case 'create':{
const chars = 'abcdefghijklmnopqrstuvwxyz0123456789'
- let random_chars = 'r'
- for (let i = 0; i < 8; i++) {
+ let random_chars = ''
+ for (let i = 0; i < 10; i++) {
random_chars += chars.charAt(Math.floor(Math.random() * chars.length));
}
- let invite_link = this.invite_URL + random_chars + Date.now();
- const time = new Date().toLocaleTimeString('en-US', {hour12: false});
-
+ let code = random_chars
await knex.query('_invite')
// @ts-expect-error
- .insert({link: invite_link, created_at: new Date().toLocaleTimeString('en-US', {hour12: false})})
-
- ctx.context.invite_links = invite_links
+ .insert({code: code})
return this.return(ctx, undefined, location='/invite')
+ }
+ case 'register': {
+ const invite_code = ctx.args.get('code')
+ if (!invite_code)
+ return
+
+ let [invite, err] = await knex
+ .query('_invite')
+ .select('used')
+ .where('code', invite_code)
+ .first()
+ .then(unpack)
+
+ if (!err && !invite?.used){
+ ctx.context.invite_code = invite_code
+ return this.return_html(ctx, 'register', undefined, 500, 200, {
+ "Set-Cookie": this.del_cookie('auth')
+ })
+ }
+ return this.return(ctx, undefined, "/")
+ }
+ case 'create_acc':{
+ if (ctx.data)
+ {
+ let form: {invite_code?: string, username?: string, password?: string, minecraft_name?: string} = ctx.data.form
+ if (form.username && form.password && form.invite_code) {
+ form.username = form.username.substring(0, 32)
+
+ this.addUser(form.username, form.password, async (id?: number, err?: Error) => {
+ // if invalid credentials
+ if (err) {
+ ctx.context.auth_err = err
+ return this.return_html(ctx, 'login')
+ }
+ // success
+ else {
+ let auth = Buffer.from(form.username+":"+form.password).toString('base64')
+ await knex
+ .query('_invite')
+ // @ts-expect-error
+ .update({
+ used: true,
+ user_id: id
+ })
+ .where('code', form.invite_code)
+ .then()
+ if (form.minecraft_name)//If a minecraft name was entered
+ {
+ await knex
+ .query('_minecraft_minecraft')
+ // @ts-expect-error
+ .insert({minecraft_name: form.minecraft_name, user_id: id})
+ }
+
+ return this.return_html(ctx, 'login', undefined, 500, 303, {
+ "Location": "/",
+ "Set-Cookie": this.set_cookie('auth', 'Basic '+auth, true)
+ })
+ }
+ })
+ }
+ }
+ return
+ }
default: {
return this.return_file(ctx, location)
}
}
}
+
+ private hash_pw(password: string): string {
+ return crypto.pbkdf2Sync(password, this.salt, 10000, 128, 'sha512').toString('base64')
+ }
+
+ addUser(name: User['name'], password: User['password'], callback: (id?: number, err?: Error) => void) {
+ let [knex]: [Knex] = this.get_dependencies('Knex')
+
+ password = this.hash_pw(password)
+ // Check if username is already taken
+ this.exists(name, (exists, err) => {
+ if (err) return callback(undefined, err)
+ if (exists) return callback(undefined, new Error("Username already taken"))
+ // add user to db
+ knex.query('user')
+ // @ts-expect-error
+ .insert({name, password, pfp_code: `seed=${name}`})
+ .then((id) => callback(id[0] as unknown as number), (err) => callback(undefined, err))
+ })
+ }
+
+ private exists(name: User['name'], callback: (exists: boolean, err?: Error) => void): void {
+ let [knex]: [Knex] = this.get_dependencies('Knex')
+ // check if name already exists
+ knex.query('user')
+ .select('id')
+ .where('name', name)
+ .then((value) => {
+ callback(!!value.length)
+ }, (err) => {
+ callback(false, err)
+ })
+ }
}
diff --git a/src/extensions/invite/login.html b/src/extensions/invite/login.html
new file mode 100644
index 0000000..e69de29
diff --git a/src/extensions/invite/register.html b/src/extensions/invite/register.html
new file mode 100644
index 0000000..e30ec71
--- /dev/null
+++ b/src/extensions/invite/register.html
@@ -0,0 +1,34 @@
+{% extends "layout.html" %}
+
+{% block head %}
+
+{% endblock %}
+
+
+{% block body %}
+
+{% endblock %}
diff --git a/src/extensions/invite/tables.ts b/src/extensions/invite/tables.ts
index ac25d49..cefcdee 100644
--- a/src/extensions/invite/tables.ts
+++ b/src/extensions/invite/tables.ts
@@ -14,10 +14,15 @@ export default class extends Tables {
await knex.schema()
.createTable('_invite', (table) => {
table.increments('id').primary()
- table.string('link').notNullable()
- table.timestamp('created_at').notNullable().defaultTo(knex.raw('CURRENT_TIMESTAMP'))
+ table.string('code').notNullable()
+ table.datetime('created_at').notNullable().defaultTo(knex.raw('CURRENT_TIMESTAMP'))
table.boolean('used').notNullable().defaultTo(false)
+ table.integer('user_id')
+ table.foreign('user_id', 'fk_user_id').references('_root_user.id')
})
+ await knex.query('_invite')
+ // @ts-expect-error
+ .insert({code: 'admin'})
},
})
diff --git a/src/extensions/minecraft/index.html b/src/extensions/minecraft/index.html
index c0d87d1..dd55a7d 100644
--- a/src/extensions/minecraft/index.html
+++ b/src/extensions/minecraft/index.html
@@ -1,4 +1,13 @@
{% extends "extension.html" %}
{% block body %}
+