Init + SSO registration
Signed-off-by: Georg <georg@lysergic.dev>
This commit is contained in:
commit
d2e8fcd2b5
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
__pycache__/
|
1
README.md
Normal file
1
README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
This is a prototype allowing users to register with all of our services in a single place.
|
25
README.old.md
Normal file
25
README.old.md
Normal file
@ -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.
|
||||||
|
|
64
flaskapp.py
Normal file
64
flaskapp.py
Normal file
@ -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)
|
16
forms.py
Normal file
16
forms.py
Normal file
@ -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')
|
106
irc_register.py
Normal file
106
irc_register.py
Normal file
@ -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")
|
45
irc_verify.py
Normal file
45
irc_verify.py
Normal file
@ -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"
|
||||||
|
|
13
requirements.old.txt
Normal file
13
requirements.old.txt
Normal file
@ -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
|
17
requirements.txt
Normal file
17
requirements.txt
Normal file
@ -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
|
44
templates/register.html
Normal file
44
templates/register.html
Normal file
@ -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.
|
Loading…
Reference in New Issue
Block a user