From ffa3b347392411e46823d7a6eea3047e866570b7 Mon Sep 17 00:00:00 2001 From: furo Date: Sat, 15 Jan 2022 18:47:56 +0100 Subject: [PATCH] Initial commit --- .env.template | 5 ++ .gitignore | 134 ++++++++++++++++++++++++++++++++++++++++++++++ README.md | 62 +++++++++++++++++++++ captcha.sh | 93 ++++++++++++++++++++++++++++++++ index.js | 102 +++++++++++++++++++++++++++++++++++ package.json | 18 +++++++ public/index.html | 17 ++++++ 7 files changed, 431 insertions(+) create mode 100644 .env.template create mode 100644 .gitignore create mode 100644 README.md create mode 100755 captcha.sh create mode 100644 index.js create mode 100644 package.json create mode 100644 public/index.html diff --git a/.env.template b/.env.template new file mode 100644 index 0000000..0a58f1d --- /dev/null +++ b/.env.template @@ -0,0 +1,5 @@ +# Where is the GLAuth sqlite DB located? +GLAUTH_DB="" + +# Which port should the server run on? +PORT=8080 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2920621 --- /dev/null +++ b/.gitignore @@ -0,0 +1,134 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + + +captcha.png +package-lock.json \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..7037ed9 --- /dev/null +++ b/README.md @@ -0,0 +1,62 @@ +# qwik-register + +## GLAuth installation + +``` +git clone https://github.com/glauth/glauth.git +cd glauth +make fast +make plugins +``` + +## GLAuth config + +```ini +[ldap] + enabled = true + listen = "0.0.0.0:3893" + +[ldaps] + enabled = false + listen = "0.0.0.0:3894" + cert = "certs/server.crt" + key = "certs/server.key" + +[backend] + datastore = "plugin" + plugin = "sqlite.so" + pluginhandler = "NewSQLiteHandler" + baseDN = "dc=glauth,dc=com" + database = "users.db" + + nameformat = "cn" + groupformat = "ou" +``` + +## Pre database setup + +```sql +CREATE TABLE users ( + uidnumber INTEGER PRIMARY KEY autoincrement, + id INTEGER, + name TEXT NOT NULL, + primarygroup INTEGER NOT NULL, + othergroups TEXT DEFAULT '', + givenname TEXT DEFAULT '', + sn TEXT DEFAULT '', + mail TEXT DEFAULT '', + loginshell TYEXT DEFAULT '', + homedirectory TEXT DEFAULT '', + disabled SMALLINT DEFAULT 0, + passsha256 TEXT DEFAULT '', + passbcrypt TEXT DEFAULT '', + otpsecret TEXT DEFAULT '', + yubikey TEXT DEFAULT '', + custattr TEXT DEFAULT '{}'); + +INSERT INTO groups(name, gidnumber) VALUES('users', 0); +INSERT INTO groups(name, gidnumber) VALUES('admins', 10); +INSERT INTO groups(name, gidnumber) VALUES('root', 100); + +INSERT INTO includegroups(parentgroupid, includegroupid) VALUES(10, 0); +``` \ No newline at end of file diff --git a/captcha.sh b/captcha.sh new file mode 100755 index 0000000..7885858 --- /dev/null +++ b/captcha.sh @@ -0,0 +1,93 @@ +#!/bin/sh + +# This script is an example captcha script. +# It takes the text to recognize in the captcha image as a parameter. +# It return the image binary as a result. ejabberd support PNG, JPEG and GIF. + +# The whole idea of the captcha script is to let server admins adapt it to +# their own needs. The goal is to be able to make the captcha generation as +# unique as possible, to make the captcha challenge difficult to bypass by +# a bot. +# Server admins are thus supposed to write and use their own captcha generators. + +# This script relies on ImageMagick. +# It is NOT compliant with ImageMagick forks like GraphicsMagick. + +INPUT=$1 + +for n in $(od -A n -t u2 -N 48 /dev/urandom); do RL="$RL$n "; done +get_random () +{ + R=${RL%% *} + RL=${RL#* } +} + +get_random +WAVE1_AMPLITUDE=$((2 + R % 5)) +get_random +WAVE1_LENGTH=$((50 + R % 25)) +get_random +WAVE2_AMPLITUDE=$((2 + R % 5)) +get_random +WAVE2_LENGTH=$((50 + R % 25)) +get_random +WAVE3_AMPLITUDE=$((2 + R % 5)) +get_random +WAVE3_LENGTH=$((50 + R % 25)) +get_random +W1_LINE_START_Y=$((10 + R % 40)) +get_random +W1_LINE_STOP_Y=$((10 + R % 40)) +get_random +W2_LINE_START_Y=$((10 + R % 40)) +get_random +W2_LINE_STOP_Y=$((10 + R % 40)) +get_random +W3_LINE_START_Y=$((10 + R % 40)) +get_random +W3_LINE_STOP_Y=$((10 + R % 40)) + +get_random +B1_LINE_START_Y=$((R % 40)) +get_random +B1_LINE_STOP_Y=$((R % 40)) +get_random +B2_LINE_START_Y=$((R % 40)) +get_random +B2_LINE_STOP_Y=$((R % 40)) +#B3_LINE_START_Y=$((R % 40)) +#B3_LINE_STOP_Y=$((R % 40)) + +get_random +B1_LINE_START_X=$((R % 20)) +get_random +B1_LINE_STOP_X=$((100 + R % 40)) +get_random +B2_LINE_START_X=$((R % 20)) +get_random +B2_LINE_STOP_X=$((100 + R % 40)) +#B3_LINE_START_X=$((R % 20)) +#B3_LINE_STOP_X=$((100 + R % 40)) + +get_random +ROLL_X=$((R % 40)) + +convert -size 180x60 xc:none -pointsize 40 \ + \( -clone 0 -fill white \ + -stroke black -strokewidth 4 -annotate +0+40 "$INPUT" \ + -stroke white -strokewidth 2 -annotate +0+40 "$INPUT" \ + -roll +$ROLL_X+0 \ + -wave "$WAVE1_AMPLITUDE"x"$WAVE1_LENGTH" \ + -roll -$ROLL_X+0 \) \ + \( -clone 0 -stroke black \ + -strokewidth 1 -draw \ + "line $B1_LINE_START_X,$B1_LINE_START_Y $B1_LINE_STOP_X,$B1_LINE_STOP_Y" \ + -strokewidth 1 -draw \ + "line $B2_LINE_START_X,$B2_LINE_START_Y $B2_LINE_STOP_X,$B2_LINE_STOP_Y" \ + -wave "$WAVE2_AMPLITUDE"x"$WAVE2_LENGTH" \) \ + \( -clone 0 -stroke white \ + -strokewidth 2 -draw "line 0,$W1_LINE_START_Y 140,$W1_LINE_STOP_Y" \ + -strokewidth 2 -draw "line 0,$W2_LINE_START_Y 140,$W2_LINE_STOP_Y" \ + -strokewidth 2 -draw "line 0,$W3_LINE_START_Y 140,$W3_LINE_STOP_Y" \ + -wave "$WAVE3_AMPLITUDE"x"$WAVE3_LENGTH" \) \ + -flatten -crop 140x60 +repage -quality 90 -depth 8 png:- diff --git a/index.js b/index.js new file mode 100644 index 0000000..b8c658f --- /dev/null +++ b/index.js @@ -0,0 +1,102 @@ +import Database from 'better-sqlite3' +import express from 'express' +import crypto from 'crypto' +import dotenv from 'dotenv' + +import { exec } from 'child_process' + +dotenv.config() + +const app = express() +const port = process.env.PORT +let valid = {} +let glauth = undefined + +console.log(process.env) + +dbInit() + +app.use(express.urlencoded({ + extended: true +})) + +app.use(express.static('public')) + +app.post('/register', (req, res) => { + // Was input sent? + if(!req.body.username) + return(res.send("No username entered!")) + + if(!req.body.password) + return(res.send("No password entered!")) + + if(!req.body.password) + return(res.send("No captcha entered!")) + + // does the username match the requirements + if(!(/^(?=[a-zA-Z0-9]{2,20}$).*$/.test(req.body.username))) + return(res.send("Username does not match the requirements")) + + // is captcha valid + if(!valid[req.body.captcha]) + return(res.send("Invalid captcha!")) + + const captchaAge = Math.abs((valid[req.body.captcha].getTime() - new Date().getTime())/1000) + + if(captchaAge > 600) + return(res.send("Invalid captcha!")) + + // expire the captcha + delete valid[req.body.captcha] + + // Does user already exist? + if(glauth.prepare(`SELECT * FROM users WHERE name = ?`).get(req.body.username)) + return(res.send("User already exists")) + + // Create the user! + glauth.prepare(` + INSERT INTO users( + name, primarygroup, passsha256 + ) VALUES(?, 0, ?) + `).run(req.body.username, crypto.createHash('sha256').update(req.body.password).digest('hex')) + + console.log(`>>> User: ${req.body.username} was succesfully created!`) + res.send("Account registered!") + + res.end() +}) + +app.get('/captcha', async (req, res) => { + const captcha = crypto.randomBytes(3).toString('hex') + await execawait(`./captcha.sh ${captcha} > captcha.png`) + + // Make it valid for 10 minutes + valid[captcha] = new Date() + + // Send the captcha image + res.contentType('image/png'); + res.sendFile('captcha.png', { + root: './' + }); +}) + +app.listen(port); +console.log('Server started at http://localhost:' + port); + + +function execawait(cmd) { + return new Promise((resolve, reject) => { + exec(cmd, (error, stdout, stderr) => { + if (error) { + console.warn(error); + } + resolve(stdout ? stdout : stderr); + }); + });7 +} + +function dbInit() { + glauth = new Database(process.env.GLAUTH_DB, {}) + + console.log(`Loaded in GLAuth - users.db`) +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..fdb07a0 --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "name": "qwik-register", + "version": "1.0.0", + "description": "", + "main": "index.js", + "type": "module", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "better-sqlite3": "^7.4.6", + "dotenv": "^12.0.3", + "express": "^4.17.2", + "expresss": "^0.0.0" + } +} diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..62e3fba --- /dev/null +++ b/public/index.html @@ -0,0 +1,17 @@ + + + +
+
+
+
+ +
+
+ +
+ +
\ No newline at end of file