summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorg2021-09-01 12:55:44 +0200
committerGeorg2021-09-01 12:55:44 +0200
commitd2e8fcd2b5949c7836feaf559cd65c5062a7748c (patch)
treea46305087626f5362e4719f255f296e77056b010
downloadwebreg-d2e8fcd2b5949c7836feaf559cd65c5062a7748c.tar.gz
webreg-d2e8fcd2b5949c7836feaf559cd65c5062a7748c.tar.bz2
webreg-d2e8fcd2b5949c7836feaf559cd65c5062a7748c.zip
Init + SSO registration
Signed-off-by: Georg <georg@lysergic.dev>
-rw-r--r--.gitignore1
-rw-r--r--README.md1
-rw-r--r--README.old.md25
-rw-r--r--flaskapp.py64
-rw-r--r--forms.py16
-rw-r--r--irc_register.py106
-rw-r--r--irc_verify.py45
-rw-r--r--requirements.old.txt13
-rw-r--r--requirements.txt17
-rw-r--r--templates/register.html44
10 files changed, 332 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c18dd8d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+__pycache__/
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d0cd2e4
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+This is a prototype allowing users to register with all of our services in a single place.
diff --git a/README.old.md b/README.old.md
new file mode 100644
index 0000000..512403e
--- /dev/null
+++ b/README.old.md
@@ -0,0 +1,25 @@
+# Liberta Casa
+
+This has a series of little enhancements I have taken up as pet projects.
+
+### Registration Page
+
+##### Theoreticals
+
+It includes the following technologies: oragono IRCd, flask, a python bot using irctokens
+
+It consists of the following flow.
+
+1. A user shall go on to the [registration](https://liberta.casa/register.html) (placeholder). They will enter the details and click on Register.
+ * The Website is generated using `flask` and the form is generated using `wtforms, flask_wtf`.
+ * It shall capture the username and password entered by the user and POST it to the same route.
+ * The username and password already have validators to ensure they fit within the parameters if the oragono ircd services. eg. NICKLEN 32
+2. The bot will be triggered and it shall carry the information provided as arguments by connecting to the IRCd.
+3. It will use the `USER` ,`NICK ` commands to register the connection on the IRCd then assign the nickname same as that passed on by the flask route.
+ * If no lines are recieved it shall throw a server error.
+ * If the nickname is already in use then the received the `433` code will be captured and translated back to the user as suggestion to retry with a different username
+ * If the `NICK` command is successful it shall proceed to the next step
+4. Using the `PRIVMSG` command the bot shall register for the user and it shall read for `NOTICE` indicating successful account creation and carry that back to the flask app and be shown to the user.
+5. TODO: If this fails add and unconditional which exits or it will be an infinite loop.
+6. After this success the bot shall Die and the user will be redirected to the page which contains Rules and FAQs about login and features.
+
diff --git a/flaskapp.py b/flaskapp.py
new file mode 100644
index 0000000..cfa21e8
--- /dev/null
+++ b/flaskapp.py
@@ -0,0 +1,64 @@
+from flask import Flask, render_template, url_for, request, redirect, flash
+from forms import RegistrationForm
+from irc_register import ircregister
+#from irc_verify import ircverify
+
+
+app = Flask(__name__)
+app.config['SECRET_KEY'] = '$secret' #remove later
+
+@app.route('/')
+def hello():
+ return render_template('home.html')
+
+@app.route('/kiwi')
+def kiwi():
+ return redirect("https://liberta.casa/kiwi/")
+@app.route('/kiwi/')
+def kiwinick(nick, show_password_box):
+ nick = request.args.get('nick', None)
+ show_password_box = requests.args.get('show_password_box', None)
+ return redirect("https://liberta.casa/kiwi/")
+
+@app.route('/register', methods=['GET', 'POST'])
+def register():
+ form = RegistrationForm()
+ if request.method == 'POST':
+
+ username = request.form.get('username')
+ email = request.form.get('email')
+ password = request.form.get('password')
+# email = request.form.get('email') add password arg to ircregisterfunction
+ response = ircregister(username, password, email)
+ if response == "server failure":
+ flash("Server Unavailable")
+ elif response == "433":
+ flash("Username already taken. Please select a different username")
+ elif response == "success":
+ return redirect(url_for('kiwinick', nick=username, show_password_box='true'))
+ elif response == "failure":
+ flash("Failure! Please try after some time or use NickServ.")
+
+ return render_template('register.html', title='Register', form=form)
+
+#@app.route('/verify', methods=['GET', 'POST'])
+#def verify():
+# form = VerificationForm()
+# if request.method == 'POST':
+#
+# username = request.form.get('username')
+# verif_code = request.form.get('verif_code')
+# response = ircverify(username, verif_code)
+# if response == "server failure":
+# flash("Server Unavailable")
+# elif response == "433":
+# flash("Username under use. Please check your username or visit us for help")
+# elif response == "success":
+# return redirect(url_for('kiwi'))
+# elif response == "failure":
+# flash("Failure! Please try after some time or use NickServ.")
+# return render_template('verify.html', title='Verify', form=form)
+
+
+if __name__ == '__main__':
+ app.run(debug=True)
diff --git a/forms.py b/forms.py
new file mode 100644
index 0000000..6e55f64
--- /dev/null
+++ b/forms.py
@@ -0,0 +1,16 @@
+from flask_wtf import FlaskForm
+from wtforms import StringField, PasswordField, SubmitField
+from wtforms.validators import DataRequired, Length, EqualTo, Email
+
+
+class RegistrationForm(FlaskForm):
+ username = StringField('Username', validators=[DataRequired(), Length(min=1, max=32)])
+ email = StringField('Email', validators=[DataRequired(), Email()])
+ password = PasswordField('Password', validators=[DataRequired()])
+ confirm_password = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')])
+ submit = SubmitField('Register')
+
+#class VerificationForm(FlaskForm):
+# username = StringField('Username', validators=[DataRequired(), Length(min=1, max=32)])
+# verif_code = StringField('Verification Code', validators=[DataRequired()])
+# submit = SubmitField('Verify')
diff --git a/irc_register.py b/irc_register.py
new file mode 100644
index 0000000..fcad711
--- /dev/null
+++ b/irc_register.py
@@ -0,0 +1,106 @@
+import socket, irctokens
+import requests
+import re
+
+def ircregister(username, password, email):
+ # define the variables
+ d = irctokens.StatefulDecoder()
+ e = irctokens.StatefulEncoder()
+ s = socket.socket()
+
+ #connecting to the server
+ s.connect(("127.0.0.1", 6667))
+
+ #defining the send function with proper formatting
+ def _send(line):
+ print(f"> {line.format()}")
+ e.push(line)
+ while e.pending():
+ e.pop(s.send(e.pending()))
+
+ # registering the connection to the server
+
+ _send(irctokens.build("USER", [username, "0", "*", username]))
+ _send(irctokens.build("NICK", [username]))
+
+ server = 'http://192.168.0.115:8880'
+ realm = 'devel'
+ tokenurl = 'http://localhost/kctoken'
+ usererr = 'An error occured.'
+ emailverified = False
+ firstname = 'Foo'
+ lastname = 'Bar'
+
+ # go through the cases
+
+ while True:
+ lines = d.push(s.recv(1024))
+
+ if lines == None: #if nothing is received from server
+ return "server error"
+ break
+
+ for line in lines:
+ print(f"< {line.format()}")
+
+ if line.command == "433": # if nickname already in use
+ return "433"
+
+ elif line.command == "005": # when 005 is received pass the nickserv register command command
+ _send(irctokens.build("PRIVMSG", ["NickServ", f"REGISTER {password}"]))
+ if line.command == 'NOTICE' and line.params == [username, f"Account created"]:
+ _send(irctokens.build("QUIT"))
+ try:
+ tokendl = requests.get(tokenurl)
+ tokendata = tokendl.json()
+ token = tokendata['access_token']
+ url = server + '/auth/admin/realms/' + realm + '/users'
+ except:
+ print("ERROR: Keycloak token could not be installed.")
+ if re.match(r"[^@]+@[^@]+\.[^@]+", email):
+ payload = {
+ "firstName": firstname,
+ "lastName": lastname,
+ "email": email,
+ "enabled": "true",
+ "username": username,
+ "credentials": [{"type": "password", "value": password, "temporary": emailverified,}],
+ "emailVerified": emailverified
+ }
+ response = requests.post(
+ url,
+ headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer ' + token},
+ json = payload
+ )
+ print("Keycloak: HTTP Status ", response.status_code)
+ try:
+ print("Keycloak: Response Text: ", response.text)
+ except:
+ print("Keycloak: No or invalid response text. This is not an error.")
+ try:
+ print("Keycloak: Response JSON: ", response.json())
+ except:
+ print("Keycloak: No or invalid response JSON. This it not an error.")
+ status = response.status_code
+ if status == 201:
+ print(" SSO User " + username + " created.")
+ if status == 400:
+ print("ERROR: Keycloak indicated that the request is invalid.")
+ if status == 401:
+ print("ERROR: Fix your Keycloak API credentials and/or client roles, doh.")
+ if status == 403:
+ print("ERROR: Keycloak indicated that the authorization provided is not enough to access the resource.")
+ if status == 404:
+ print("ERROR: Keycloak indicated that the requested resource does not exist.")
+ if status == 409:
+ print("ERROR: Keycloak indicated that the resource already exists or \"some other coonflict when processing the request\" occured.")
+ if status == 415:
+ print("ERROR: Keycloak indicated that the requested media type is not supported.")
+ if status == 500:
+ print("ERROR: Keycloak indicated that the server could not fullfill the request due to \"some unexpected error \".")
+ else:
+ print('Invalid email address supplied.')
+
+ return "success"
+
+# register("hello", "test")
diff --git a/irc_verify.py b/irc_verify.py
new file mode 100644
index 0000000..ff15818
--- /dev/null
+++ b/irc_verify.py
@@ -0,0 +1,45 @@
+import socket, irctokens
+
+
+def ircverify(username, verif_code):
+ # define the variables
+ d = irctokens.StatefulDecoder()
+ e = irctokens.StatefulEncoder()
+ s = socket.socket()
+
+ #connecting to the server
+ s.connect(("127.0.0.1", 6667))
+
+ #defining the send function with proper formatting
+ def _send(line):
+ print(f"> {line.format()}")
+ e.push(line)
+ while e.pending():
+ e.pop(s.send(e.pending()))
+ # registering the connection to the server
+
+ _send(irctokens.build("USER", [username, "0", "*", username]))
+ _send(irctokens.build("NICK", [username]))
+
+ # go through the cases
+
+ while True:
+ lines = d.push(s.recv(1024))
+
+ if lines == None: #if nothing is received from server
+ return "server error"
+ break
+
+ for line in lines:
+ print(f"< {line.format()}")
+
+ if line.command == "433": # if nickname already in use
+ return "433"
+
+ elif line.command == "005": # when 005 is received pass the nickserv register command command
+ _send(irctokens.build("PRIVMSG", ["NickServ", f"VERIFY {username} {verif_code}"]))
+
+ if line.command == "NOTICE" and line.params == [username, "Account created"]: # if Services respond with appropriate notice NOTICE
+ _send(irctokens.build("QUIT"))
+ return "success"
+
diff --git a/requirements.old.txt b/requirements.old.txt
new file mode 100644
index 0000000..daa45d8
--- /dev/null
+++ b/requirements.old.txt
@@ -0,0 +1,13 @@
+click==7.1.2
+dnspython==1.16.0
+email-validator==1.1.1
+Flask==1.1.2
+Flask-WTF==0.14.3
+gunicorn==20.0.4
+idna==2.9
+irctokens>=1.0.1
+itsdangerous==1.1.0
+Jinja2==2.11.2
+MarkupSafe==1.1.1
+Werkzeug==1.0.1
+WTForms==2.3.1
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..db3653d
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,17 @@
+certifi==2021.5.30
+charset-normalizer==2.0.4
+click==7.1.2
+dnspython==1.16.0
+email-validator==1.1.1
+Flask==1.1.2
+Flask-WTF==0.14.3
+gunicorn==20.0.4
+idna==2.9
+irctokens==2.0.0
+itsdangerous==1.1.0
+Jinja2==2.11.2
+MarkupSafe==1.1.1
+requests==2.26.0
+urllib3==1.26.6
+Werkzeug==1.0.1
+WTForms==2.3.1
diff --git a/templates/register.html b/templates/register.html
new file mode 100644
index 0000000..9c535e3
--- /dev/null
+++ b/templates/register.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <meta charset="UTF-8">
+ <title>Register</title>
+<style>
+ body {
+ background-color: black;
+ color: white;
+ }
+</style>
+</head>
+
+<body>
+ {% for message in get_flashed_messages() %}
+ {{ message }}
+ {% endfor %}
+<pre>
+┬ ┌┬┐ ┬─┐ ┬─┐ ┬─┐ ┌┐┐ ┬─┐
+│ │ │─│ │─ │┬┘ │ │─┤
+┘─┘ └┴┘ │─┘ ┴─┘ │└┘ ┘ ┘ │
+
+┌─┐ ┬─┐ ┐─┐ ┬─┐
+│ │─┤ └─┐ │─┤
+└─┘ ┘ │ ──┘ ┘ │
+
+<form method="POST" action="/register">
+ {{ form.hidden_tag() }}
+ <fieldset>
+ <legend>Sign Up</legend>
+ {{ form.username.label }}
+ {{ form.username }}
+ {{ form.email.label }}
+ {{ form.email }}
+ {{ form.password.label }}
+ {{ form.password }}
+ {{ form.confirm_password.label }}
+ {{ form.confirm_password }}
+ </fieldset>
+ {{ form.submit }}
+</form>
+
+If you already have an account please login to the IRC using SASL.