Register and resend

This commit is contained in:
Dita Aji Pratama 2025-01-20 17:52:27 +07:00
parent 32d2fa6059
commit 2f4b9fb1a3
9 changed files with 265 additions and 1 deletions

View File

@ -5,12 +5,18 @@
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
# You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/. # You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.
from bottle import Bottle, route from bottle import Bottle, route, request, response, redirect
from config import directory from config import directory
import json
import templates.plain.main as template_public import templates.plain.main as template_public
import templates.postcard.main as template_email
import modules.public.home as public_home import modules.public.home as public_home
import modules.api.auth as api_auth
app = Bottle() app = Bottle()
@app.route('/') @app.route('/')
@ -21,3 +27,38 @@ def index():
} }
} }
return public_home.main().html(params) return public_home.main().html(params)
@app.route('/api/auth/registration/register/<roles>', method=['OPTIONS', 'POST'])
def index(roles):
try:
if request.method == 'OPTIONS':
return None
else:
response.content_type = 'application/json'
params = request.json
params["roles" ] = roles
params["mako" ] = {
"email" : template_email.main(directory.page["email"], "verification")
}
return json.dumps(api_auth.auth().register(params), indent = 2).encode()
except Exception as e:
print(str(e),flush=True)
return json.dumps({}, indent = 2).encode()
@app.route('/api/auth/registration/resend', method='GET')
def index():
try:
if request.method == 'OPTIONS':
return None
else:
response.content_type = 'application/json'
params = {
"email" : request.query.email,
"mako" : {
"email" : template_email.main(directory.page["email"], "verification")
}
}
return json.dumps(api_auth.auth().resend(params), indent = 2).encode()
except Exception as e:
print(str(e),flush=True)
return json.dumps({}, indent = 2).encode()

136
modules/api/auth.py Normal file
View File

@ -0,0 +1,136 @@
import mysql.connector as mariadb
from mako.template import Template
from bottle import request
from config import database, globalvar
import bcrypt
import datetime
from scripts import loggorilla, saltedkey, googly, tokenguard, sendwave
import procedure.validation as procedure_validation
import procedure.webmail as procedure_webmail
class auth:
def __init__(self):
self.db_main = mariadb.connect(**database.db_main)
self.cursor = self.db_main.cursor(dictionary=True)
self.smtpconfig = globalvar.smtpconfig
def register(self, params):
APIADDR = "/api/auth/registration/register/:roles"
loggorilla.prcss(APIADDR, "Define parameters")
response = {}
captcha = params["captcha" ]
username = params["username" ].lower()
email = params["email" ].lower()
password = params["password" ]
roles = params["roles" ]
self.cursor.execute("BEGIN;")
try:
loggorilla.prcss(APIADDR, "Get dependency data")
self.cursor.execute(f"SELECT id, name FROM `auth_roles` WHERE auth_roles.name = %s ; ", (roles,) )
result_roles = self.cursor.fetchone()
loggorilla.prcss(APIADDR, "Process parameters")
hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
token = saltedkey.token(username, hashed)
if globalvar.production == True:
captcha_r = googly.recaptcha(captcha, globalvar.reCAPTCHA['server'])
score = captcha_r["score"]
else:
captcha_r = 'dev mode'
score = 0.9
loggorilla.fyinf(APIADDR, f'captcha_r : {captcha_r}')
loggorilla.fyinf(APIADDR, f'score : {score}')
loggorilla.prcss(APIADDR, "Validation")
result_validation = procedure_validation.validation().register(APIADDR, captcha, score, roles, username, password, email)
if result_validation['status'] == "valid":
loggorilla.prcss(APIADDR, "Inserting")
self.cursor.execute("INSERT INTO `auth` VALUES (%s, %s);", (token, hashed) )
self.cursor.execute("INSERT INTO `auth_profile` VALUES (DEFAULT, %s, %s, %s, NULL);", (token, username, email) )
auth_profile_lastrowid = self.cursor.lastrowid
self.cursor.execute("INSERT INTO `auth_profile_verification` VALUES (DEFAULT, %s, 'email', 0);", (auth_profile_lastrowid,) )
self.cursor.execute("INSERT INTO `auth_profile_roles` VALUES (DEFAULT, %s, %s);", (auth_profile_lastrowid, result_roles['id']) )
loggorilla.prcss(APIADDR, "Generate URL")
expired = globalvar.verification_link_expiration
expired_isoformat = expired.isoformat()
payload = {
"token" : token,
"expired": expired_isoformat
}
token_encrypt = tokenguard.encode(payload, globalvar.ssh['key']['private'], globalvar.ssh['passphrase'])
verification_url = globalvar.verification_url(token_encrypt)
notme_url = globalvar.notme_url(token_encrypt)
loggorilla.prcss(APIADDR, "Sending email")
webmail_data = {"verify": verification_url, "notme": notme_url}
result_webmail = procedure_webmail.webmail().verification(APIADDR, params, webmail_data)
self.smtpconfig['to' ] = email
self.smtpconfig['subject' ] = result_webmail['subject']
self.smtpconfig['text' ] = result_webmail['text' ]
self.smtpconfig['html' ] = result_webmail['html' ]
sendwave.smtp(self.smtpconfig)
loggorilla.prcss(APIADDR, "Giving response")
response["status" ] = "success"
response["desc" ] = "Register success. Check email for verification."
response["data" ] = {
"recaptcha":captcha_r
}
else:
response = result_validation
except Exception as e:
self.cursor.execute("ROLLBACK;")
loggorilla.error(APIADDR, str(e) )
response["status" ] = "failed"
response["desc" ] = "Internal Server Error. Please contact us if you still have an error."
finally:
self.cursor.execute("COMMIT;")
self.cursor.close()
self.db_main.close()
return response
def resend(self, params):
APIADDR = "/api/auth/registration/resend"
loggorilla.prcss(APIADDR, "Define parameters")
response = {}
email = params["email"].lower()
try:
loggorilla.prcss(APIADDR, "Get data for checking")
self.cursor.execute(f"SELECT COUNT(*) AS `count`, auth_profile.token, auth_profile.email FROM auth_profile_verification INNER JOIN auth_profile ON auth_profile.id = auth_profile_verification.profile WHERE auth_profile.email = %s AND auth_profile_verification.type = 'email' AND auth_profile_verification.verified = 0 ; ", (email,) )
result_unverified = self.cursor.fetchone()
token = result_unverified["token"].decode()
if result_unverified["count"] >= 1:
loggorilla.prcss(APIADDR, "Generate URL")
expired = globalvar.verification_link_expiration
expired_isoformat = expired.isoformat()
payload = {
"token" : token,
"expired": expired_isoformat
}
token_encrypt = tokenguard.encode(payload, globalvar.ssh['key']['private'], globalvar.ssh['passphrase'])
verification_url = globalvar.verification_url(token_encrypt)
notme_url = globalvar.notme_url(token_encrypt)
loggorilla.prcss(APIADDR, "Sending email")
webmail_data = {"verify": verification_url, "notme": notme_url}
result_webmail = procedure_webmail.webmail().verification(APIADDR, params, webmail_data)
self.smtpconfig['to' ] = email
self.smtpconfig['subject' ] = result_webmail['subject']
self.smtpconfig['text' ] = result_webmail['text' ]
self.smtpconfig['html' ] = result_webmail['html' ]
sendwave.smtp(self.smtpconfig)
loggorilla.prcss(APIADDR, "Giving response")
response["status" ] = "success"
response["desc" ] = "Resend success. Check email for verification."
else:
response["status" ] = "failed"
response["desc" ] = "The parameters seems suspicious and you are not authorized for that"
except Exception as e:
loggorilla.error(APIADDR, str(e) )
response["status" ] = "failed"
response["desc" ] = "Internal Server Error. Please contact us if you still have an error. for detail"
finally:
self.cursor.close()
self.db_main.close()
return response

1
pages/email/message.html Normal file
View File

@ -0,0 +1 @@
<p>${message}</p>

View File

@ -0,0 +1,11 @@
<h2>${header}</h2>
<p>Thanks for signing up! This is the start of an exciting journey and youre just one step away from completing your account setup to start using your profile.</p>
<p>Click the button below to verify your account and get started.</p>
<a href="${verify}" class="button">
Verify email address
</a>
<br>
<br>
<p>You are not registering this? <a href="${notme}">I'm not registering this</a></p>
<br>

11
scripts/googly.py Normal file
View File

@ -0,0 +1,11 @@
import json
import requests
def recaptcha(captcha, secret):
url = "https://www.google.com/recaptcha/api/siteverify"
myobj = {
"secret" : secret,
"response" : captcha
}
response = json.loads(requests.post(url, data = myobj).text)
return response

13
scripts/loggorilla.py Normal file
View File

@ -0,0 +1,13 @@
import datetime
def prcss(loc, msg):
print(f"[loggorilla][{datetime.datetime.now()}][\033[32mprcss\033[39m][\033[95m{loc}\033[39m] {msg}", flush=True)
def accss(loc, msg):
print(f"[loggorilla][{datetime.datetime.now()}][\033[36maccss\033[39m][\033[95m{loc}\033[39m] {msg}", flush=True)
def fyinf(loc, msg):
print(f"[loggorilla][{datetime.datetime.now()}][\033[93mfyinf\033[39m][\033[95m{loc}\033[39m] {msg}", flush=True)
def error(loc, msg):
print(f"[loggorilla][{datetime.datetime.now()}][\033[31merror\033[39m][\033[95m{loc}\033[39m] {msg}", flush=True)

5
scripts/saltedkey.py Normal file
View File

@ -0,0 +1,5 @@
import bcrypt
import hashlib
def token(username, hashed):
return hashlib.sha1( (username+username[:3]+hashed[-6:]).encode() ).hexdigest()

23
scripts/sendwave.py Normal file
View File

@ -0,0 +1,23 @@
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import smtplib
def smtp(config):
msg = MIMEMultipart('alternative')
msg['Subject' ] = config['subject' ]
msg['From' ] = config['from' ]
msg['To' ] = config['to' ]
part1 = MIMEText(config['text'], 'plain')
part2 = MIMEText(config['html'], 'html' )
msg.attach(part1)
msg.attach(part2)
smtp_server = smtplib.SMTP(config['server']['host'], config['server']['port'])
smtp_server.ehlo()
smtp_server.starttls()
smtp_server.login( config['login']['email'], config['login']['password'] )
smtp_server.sendmail('&&&&&&', config['to'], msg.as_string() )
smtp_server.quit()

23
scripts/tokenguard.py Normal file
View File

@ -0,0 +1,23 @@
from cryptography.hazmat.primitives import serialization
import jwt
def encode(payload, id_rsa, passphrase):
private_key = open(id_rsa, 'r').read()
key = serialization.load_ssh_private_key(private_key.encode(), password=passphrase)
token = jwt.encode(
payload = payload,
key = key,
algorithm = 'RS256'
)
return token
def decode(token, id_rsa):
public_key = open(id_rsa, 'r').read()
key = serialization.load_ssh_public_key(public_key.encode())
header = jwt.get_unverified_header(token)
payload = jwt.decode(
jwt = token,
key = key,
algorithms = [header['alg'], ]
)
return payload