Compare commits

...

10 Commits

25 changed files with 593 additions and 147 deletions

1
app/.gitignore vendored
View File

@ -5,3 +5,4 @@ venv/
env/ env/
.beaker/data/* .beaker/data/*
!.beaker/data/.noremove !.beaker/data/.noremove
nohup.out

View File

@ -1,24 +1,18 @@
from bottle import Bottle, get, static_file from core import template
page = { page = {
'public' :'pages/public', 'public' :'pages/public',
'email' :'pages/email' 'email' :'pages/email'
} }
app = Bottle() static = [
{
# Default staticdir "route" :"/css/<filepath:re:.*\.(css|sass|css.map)>",
"root" :"./static/css"
@app.get("/css/<filepath:re:.*\.(css|sass|css.map)>") },
def static(filepath): {
return static_file(filepath, root="./static/css") "route" :"/js/<filepath:re:.*\.(js)>",
"root" :"./static/js"
@app.get("/js/<filepath:re:.*\.(js)>") }
def static(filepath): ]
return static_file(filepath, root="./static/js") template.add(static, "templates")
# Template staticdir: plain
@app.get("/templates/plain/css/<filepath:re:.*\.(css|sass|css.map)>")
def static(filepath):
return static_file(filepath, root="./templates/plain/static/css")

View File

@ -1,11 +1,11 @@
title = "Authsquare" title = "Authsquare"
header = f"Welcome to {title}" header = f"Welcome to {title}"
copyright = "Copyright (C) 2024 Dita Aji Pratama" copyright = "Copyright (C) 2024 Dita Aji Pratama"
production = False production = False
su_mode = True forbidden_registration = ['su', 'admin']
auth_key = 'your_key' auth_key = 'your_key'
ssh = { ssh = {
"key":{ "key":{
@ -49,7 +49,7 @@ def verification_url(token):
return url return url
def change_forgot_url(token): def change_forgot_url(token):
url = f"{baseurl}/portal/change/forgot?token={token}" url = f"{baseurl}/reset?token={token}"
return url return url
menu = { menu = {

7
app/core/staticdir.py Normal file
View File

@ -0,0 +1,7 @@
from bottle import Bottle, static_file
from config import directory
app = Bottle()
for item in directory.static:
app.route(item['route'], "GET", lambda filepath, root=item['root']: static_file(filepath, root=root) )

8
app/core/template.py Normal file
View File

@ -0,0 +1,8 @@
import os
def add(dirconfig, template_directory):
template_list = [d for d in os.listdir(template_directory) if os.path.isdir(os.path.join(template_directory, d))]
for template_name in template_list:
template_module = __import__(f"{template_directory}.{template_name}.main", fromlist=["static"])
for static in getattr(template_module, "static", []):
dirconfig.append(static)

View File

@ -5,19 +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/.
import sys
from bottle import Bottle, run from bottle import Bottle, run
from beaker.middleware import SessionMiddleware from beaker.middleware import SessionMiddleware
import handler import handler
from core import staticdir
from config import server from config import server
from config import directory
app = Bottle() app = Bottle()
app.merge(handler.app) app.merge(handler.app)
app.merge(directory.app) app.merge(staticdir.app)
app = SessionMiddleware(app, server.session_opts) app = SessionMiddleware(app, server.session_opts)

View File

@ -5,7 +5,7 @@
# 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, request, response from bottle import Bottle, route, request, response, redirect
import json import json
from config import directory from config import directory
@ -18,6 +18,8 @@ import modules.public.register as public_register
import modules.public.notme as public_notme import modules.public.notme as public_notme
import modules.public.verify as public_verify import modules.public.verify as public_verify
import modules.public.login as public_login import modules.public.login as public_login
import modules.public.forgot as public_forgot
import modules.public.reset as public_reset
import modules.api.auth as api_auth import modules.api.auth as api_auth
@ -69,6 +71,44 @@ def index():
} }
return public_login.login().html(params) return public_login.login().html(params)
@app.route('/forgot')
def index():
params = {
"mako" : {
"website" : template_public.main(directory.page["public"], "forgot")
}
}
return public_forgot.forgot().html(params)
@app.route('/reset', method='GET')
def index():
params = {
"mako" : {
"website" : template_public.main(directory.page["public"], "reset")
}
}
return public_reset.reset().html(params)
@app.route('/logout')
def index():
beaker_session = request.environ.get('beaker.session')
if "token" in beaker_session:
params = {
"jwt" : beaker_session["token"],
"type" : "out"
}
response_session = api_auth.auth().session(params)
response_logout = api_auth.auth().logout(params)
if response_session['status'] == 'success' and response_logout['status'] == 'success' :
redirect('/?message=logout success')
else:
print('logout failed')
print(f"response session: {response_session['status']}")
print(f"response logout: {response_logout['status']}")
redirect('/?message=logout failed')
else:
redirect('/')
@app.route('/api/auth/registration/register/<roles>', method='POST') @app.route('/api/auth/registration/register/<roles>', method='POST')
def index(roles): def index(roles):
try: try:
@ -144,3 +184,34 @@ def index(type):
except Exception as e: except Exception as e:
print(str(e)) print(str(e))
return json.dumps({}, indent = 2).encode() return json.dumps({}, indent = 2).encode()
@app.route('/api/auth/logout', method='POST')
def index():
try:
params = request.json
response.content_type = 'application/json'
return json.dumps(api_auth.auth().logout(params), indent = 2).encode()
except Exception as e:
print(str(e))
return json.dumps({}, indent = 2).encode()
@app.route('/api/auth/password/forgot/<type>', method='POST')
def index(type):
try:
params = request.json
params["type"] = type
if type == "send":
params["mako"] = {
"email" : template_email.main(directory.page["email"], "reset")
}
elif type == "change":
params["mako"] = {
"email" : template_email.main(directory.page["email"], "message")
}
else:
pass
response.content_type = 'application/json'
return json.dumps(api_auth.auth().forgot(params), indent = 2).encode()
except Exception as e:
print(str(e))
return json.dumps({}, indent = 2).encode()

View File

@ -4,3 +4,7 @@ pip install bottle # Micro Framework
pip install gunicorn # WSGI Server Backend pip install gunicorn # WSGI Server Backend
pip install beaker # Session & caching library pip install beaker # Session & caching library
pip install mako # Template library pip install mako # Template library
pip install mysql-connector # Database
pip install bcrypt
pip install pyjwt[crypto]

View File

@ -53,9 +53,9 @@ class auth:
response["data" ] = { response["data" ] = {
"recaptcha":captcha_r "recaptcha":captcha_r
} }
elif globalvar.su_mode == False and roles == 'su': elif roles in globalvar.forbidden_registration:
response["status" ] = "failed" response["status" ] = "failed"
response["desc" ] = "Forbidden to become super user" response["desc" ] = f"Forbidden to become {roles}"
response["data" ] = { response["data" ] = {
"recaptcha":captcha_r "recaptcha":captcha_r
} }
@ -471,14 +471,16 @@ class auth:
type = params["type" ] # POST: send / change type = params["type" ] # POST: send / change
self.cursor.execute("BEGIN;") self.cursor.execute("BEGIN;")
try: try:
loggorilla.fyinf(APIADDR, f"type: {type}")
if type == "send": if type == "send":
loggorilla.prcss(APIADDR, "Define parameters inside decision") loggorilla.prcss(APIADDR, "Define parameters inside decision")
email = params["email"].lower() email = params["email"].lower()
loggorilla.prcss(APIADDR, "Get dependency data") loggorilla.prcss(APIADDR, "Get dependency data")
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.auth_profile WHERE auth_profile.email = %s AND auth_profile_verification.type = 'email' AND auth_profile_verification.verified = 1 ; ", (email,) ) 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.auth_profile WHERE auth_profile.email = %s AND auth_profile_verification.type = 'email' AND auth_profile_verification.verified = 1 ; ", (email,) )
result_verified = self.cursor.fetchone() result_verified = self.cursor.fetchone()
token = result_verified["token"].decode()
if result_verified["count"] >= 1: if result_verified["count"] >= 1:
loggorilla.prcss(APIADDR, "Get token")
token = result_verified["token"].decode()
loggorilla.prcss(APIADDR, "Generate URL") loggorilla.prcss(APIADDR, "Generate URL")
# TODO: set expired time # TODO: set expired time
expired = datetime.datetime.now() + datetime.timedelta(minutes=30) # Can be hours or minutes expired = datetime.datetime.now() + datetime.timedelta(minutes=30) # Can be hours or minutes
@ -493,14 +495,13 @@ class auth:
loggorilla.prcss(APIADDR, "Sending email") loggorilla.prcss(APIADDR, "Sending email")
self.smtpconfig['subject' ] = f"{globalvar.title} forgot password" self.smtpconfig['subject' ] = f"{globalvar.title} forgot password"
self.smtpconfig['to' ] = email self.smtpconfig['to' ] = email
self.smtpconfig['text' ] = f"Please visit this link to change password: {change_forgot_url}. Avoid the link if you are not request this." self.smtpconfig['text' ] = f"Please visit this link to reset password: {change_forgot_url}. Avoid the link if you are not request this."
self.smtpconfig['html' ] = Template(params["mako"]["email"]['template']).render( self.smtpconfig['html' ] = Template(params["mako"]["email"]['index']).render(
title = globalvar.title, title = globalvar.title,
heading = self.smtpconfig['subject'], header = globalvar.title,
image = "https://colorlib.com/etc/email-template/10/images/email.png", copyright = globalvar.copyright,
unsubscribe = "#", container = Template(params["mako"]["email"]['container']).render(
container = Template(params["mako"]["email"]['container']).render( reset = change_forgot_url
change = change_forgot_url
) )
) )
sendwave.smtp(self.smtpconfig) sendwave.smtp(self.smtpconfig)
@ -544,12 +545,11 @@ class auth:
self.smtpconfig['subject' ] = f"{globalvar.title} password change success" self.smtpconfig['subject' ] = f"{globalvar.title} password change success"
self.smtpconfig['to' ] = email self.smtpconfig['to' ] = email
self.smtpconfig['text' ] = f"You had change your password." self.smtpconfig['text' ] = f"You had change your password."
self.smtpconfig['html' ] = Template(params["mako"]["email"]['template']).render( self.smtpconfig['html' ] = Template(params["mako"]["email"]['index']).render(
title = globalvar.title, title = globalvar.title,
heading = self.smtpconfig['subject'], header = globalvar.title,
image = "https://colorlib.com/etc/email-template/10/images/email.png", copyright = globalvar.copyright,
unsubscribe = "#", container = Template(params["mako"]["email"]['container']).render(
container = Template(params["mako"]["email"]['container']).render(
message = f"You had change your password." message = f"You had change your password."
) )
) )

View File

@ -0,0 +1,30 @@
from mako.template import Template
from config import globalvar
from bottle import request
class forgot:
def __init__(self):
pass
def html(self, params):
active_page = "Forgot"
user_roles = [0]
beaker_session = request.environ.get('beaker.session')
jwt = beaker_session["token"] if "token" in beaker_session else None
if jwt is not None:
return redirect('/')
else:
return Template(params["mako"]["website"]['index']).render(
title = globalvar.title,
header = globalvar.header,
navbar = Template(params["mako"]["website"]['navbar']).render(
menu = globalvar.menu['public']['navbar'],
user_roles = user_roles,
active_page = active_page
),
footer = Template(params["mako"]["website"]['footer']).render(
copyright = globalvar.copyright,
),
container = Template(params["mako"]["website"]['container']).render()
)

View File

@ -1,30 +1,49 @@
import mysql.connector as mariadb import mysql.connector as mariadb
from mako.template import Template from mako.template import Template
from config import globalvar, database from config import globalvar, database
from bottle import request
import procedure.session as procedure_session
class home: class home:
def __init__(self): def __init__(self):
self.db_main = mariadb.connect(**database.db_main) self.db_main = mariadb.connect(**database.db_main)
self.cursor = self.db_main.cursor(dictionary=True) self.cursor = self.db_main.cursor(dictionary=True)
self.user_roles = [0] # Cari user roles disini self.user = {
"data":{
"profile":{
"username":None,
"email":None,
"phone":None,
"roles":[0]
}
}
}
def html(self, params): def html(self, params):
active_page = "Home"
active_page = "Home" allowed_roles = [0,1,2,3]
beaker_session = request.environ.get('beaker.session')
return Template(params["mako"]["website"]['index']).render( jwt = beaker_session["token"] if "token" in beaker_session else None
title = globalvar.title, self.user = procedure_session.session().user(jwt, allowed_roles) if jwt is not None else self.user
header = globalvar.header, user = self.user['data']
navbar = Template(params["mako"]["website"]['navbar']).render( if 'valid' in user and user['valid']['status'] == 0:
menu = globalvar.menu['public']['navbar'], return redirect('/logout')
user_roles = self.user_roles, else:
active_page = active_page return Template(params["mako"]["website"]['index']).render(
), title = globalvar.title,
footer = Template(params["mako"]["website"]['footer']).render( header = globalvar.header,
copyright = globalvar.copyright, navbar = Template(params["mako"]["website"]['navbar']).render(
), menu = globalvar.menu['public']['navbar'],
container = Template(params["mako"]["website"]['container']).render( user_roles = user['profile']['roles'],
greeting = f"Welcome to your new web application! This placeholder page is here to let you know that your web framework is successfully set up and ready to go. Now, it's time to start building your project. Dive into the documentation to explore the features and capabilities at your disposal." active_page = active_page
),
footer = Template(params["mako"]["website"]['footer']).render(
copyright = globalvar.copyright,
),
container = Template(params["mako"]["website"]['container']).render(
greeting = f"Welcome to your new web application! This placeholder page is here to let you know that your web framework is successfully set up and ready to go. Now, it's time to start building your project. Dive into the documentation to explore the features and capabilities at your disposal.",
user = user
)
) )
)

View File

@ -1,26 +1,30 @@
import mysql.connector as mariadb
from mako.template import Template from mako.template import Template
from config import globalvar, database from config import globalvar
from bottle import request
class login: class login:
def __init__(self): def __init__(self):
self.db_main = mariadb.connect(**database.db_main) pass
self.cursor = self.db_main.cursor(dictionary=True)
self.user_roles = [0] # Cari user roles disini
def html(self, params): def html(self, params):
active_page = "Login" active_page = "Login"
return Template(params["mako"]["website"]['index']).render( user_roles = [0]
title = globalvar.title, beaker_session = request.environ.get('beaker.session')
header = globalvar.header, jwt = beaker_session["token"] if "token" in beaker_session else None
navbar = Template(params["mako"]["website"]['navbar']).render( if jwt is not None:
menu = globalvar.menu['public']['navbar'], return redirect('/')
user_roles = self.user_roles, else:
active_page = active_page return Template(params["mako"]["website"]['index']).render(
), title = globalvar.title,
footer = Template(params["mako"]["website"]['footer']).render( header = globalvar.header,
copyright = globalvar.copyright, navbar = Template(params["mako"]["website"]['navbar']).render(
), menu = globalvar.menu['public']['navbar'],
container = Template(params["mako"]["website"]['container']).render() user_roles = user_roles,
) active_page = active_page
),
footer = Template(params["mako"]["website"]['footer']).render(
copyright = globalvar.copyright,
),
container = Template(params["mako"]["website"]['container']).render()
)

View File

@ -1,28 +1,45 @@
import mysql.connector as mariadb
from mako.template import Template from mako.template import Template
from config import globalvar, database from config import globalvar
from bottle import request
import procedure.session as procedure_session
class notme: class notme:
def __init__(self): def __init__(self):
self.db_main = mariadb.connect(**database.db_main) self.user = {
self.cursor = self.db_main.cursor(dictionary=True) "data":{
self.user_roles = [0] # Cari user roles disini "profile":{
"username":None,
"email":None,
"phone":None,
"roles":[0]
}
}
}
def html(self, params): def html(self, params):
active_page = None active_page = None
return Template(params["mako"]["website"]['index']).render( allowed_roles = [0,1,2,3]
title = globalvar.title, beaker_session = request.environ.get('beaker.session')
header = globalvar.header, jwt = beaker_session["token"] if "token" in beaker_session else None
navbar = Template(params["mako"]["website"]['navbar']).render( self.user = procedure_session.session().user(jwt, allowed_roles) if jwt is not None else self.user
menu = globalvar.menu['public']['navbar'], user = self.user['data']
user_roles = self.user_roles, if 'valid' in user and user['valid']['status'] == 0:
active_page = active_page return redirect('/logout')
), else:
footer = Template(params["mako"]["website"]['footer']).render( return Template(params["mako"]["website"]['index']).render(
copyright = globalvar.copyright, title = globalvar.title,
), header = globalvar.header,
container = Template(params["mako"]["website"]['container']).render( navbar = Template(params["mako"]["website"]['navbar']).render(
title = globalvar.title menu = globalvar.menu['public']['navbar'],
user_roles = user['profile']['roles'],
active_page = active_page
),
footer = Template(params["mako"]["website"]['footer']).render(
copyright = globalvar.copyright,
),
container = Template(params["mako"]["website"]['container']).render(
title = globalvar.title
)
) )
)

View File

@ -1,34 +1,36 @@
import mysql.connector as mariadb
from mako.template import Template from mako.template import Template
from config import globalvar, database from config import globalvar
from bottle import request
class register: class register:
def __init__(self): def __init__(self):
self.db_main = mariadb.connect(**database.db_main) pass
self.cursor = self.db_main.cursor(dictionary=True)
self.user_roles = [0] # Cari user roles disini
def html(self, params): def html(self, params):
roles = params["roles"]
roles = params["roles"] active_page = "Register"
active_page = "Register" user_roles = [0]
beaker_session = request.environ.get('beaker.session')
return Template(params["mako"]["website"]['index']).render( jwt = beaker_session["token"] if "token" in beaker_session else None
title = globalvar.title, if jwt is not None:
header = globalvar.header, return redirect('/')
navbar = Template(params["mako"]["website"]['navbar']).render( else:
menu = globalvar.menu['public']['navbar'], return Template(params["mako"]["website"]['index']).render(
user_roles = self.user_roles, title = globalvar.title,
active_page = active_page header = globalvar.header,
), navbar = Template(params["mako"]["website"]['navbar']).render(
footer = Template(params["mako"]["website"]['footer']).render( menu = globalvar.menu['public']['navbar'],
copyright = globalvar.copyright, user_roles = user_roles,
), active_page = active_page
container = Template(params["mako"]["website"]['container']).render( ),
title = globalvar.title, footer = Template(params["mako"]["website"]['footer']).render(
reCAPTCHA_client = globalvar.reCAPTCHA['client'], copyright = globalvar.copyright,
roles = roles, ),
production = globalvar.production container = Template(params["mako"]["website"]['container']).render(
title = globalvar.title,
reCAPTCHA_client = globalvar.reCAPTCHA['client'],
roles = roles,
production = globalvar.production
)
) )
)

View File

@ -0,0 +1,30 @@
from mako.template import Template
from config import globalvar
from bottle import request
class reset:
def __init__(self):
pass
def html(self, params):
active_page = "Reset"
user_roles = [0]
beaker_session = request.environ.get('beaker.session')
jwt = beaker_session["token"] if "token" in beaker_session else None
if jwt is not None:
return redirect('/')
else:
return Template(params["mako"]["website"]['index']).render(
title = globalvar.title,
header = globalvar.header,
navbar = Template(params["mako"]["website"]['navbar']).render(
menu = globalvar.menu['public']['navbar'],
user_roles = user_roles,
active_page = active_page
),
footer = Template(params["mako"]["website"]['footer']).render(
copyright = globalvar.copyright,
),
container = Template(params["mako"]["website"]['container']).render()
)

View File

@ -1,26 +1,43 @@
import mysql.connector as mariadb
from mako.template import Template from mako.template import Template
from config import globalvar, database from config import globalvar
from bottle import request
import procedure.session as procedure_session
class verify: class verify:
def __init__(self): def __init__(self):
self.db_main = mariadb.connect(**database.db_main) self.user = {
self.cursor = self.db_main.cursor(dictionary=True) "data":{
self.user_roles = [0] # Cari user roles disini "profile":{
"username":None,
"email":None,
"phone":None,
"roles":[0]
}
}
}
def html(self, params): def html(self, params):
active_page = None active_page = None
return Template(params["mako"]["website"]['index']).render( allowed_roles = [0,1,2,3]
title = globalvar.title, beaker_session = request.environ.get('beaker.session')
header = globalvar.header, jwt = beaker_session["token"] if "token" in beaker_session else None
navbar = Template(params["mako"]["website"]['navbar']).render( self.user = procedure_session.session().user(jwt, allowed_roles) if jwt is not None else self.user
menu = globalvar.menu['public']['navbar'], user = self.user['data']
user_roles = self.user_roles, if 'valid' in user and user['valid']['status'] == 0:
active_page = active_page return redirect('/logout')
), else:
footer = Template(params["mako"]["website"]['footer']).render( return Template(params["mako"]["website"]['index']).render(
copyright = globalvar.copyright, title = globalvar.title,
), header = globalvar.header,
container = Template(params["mako"]["website"]['container']).render() navbar = Template(params["mako"]["website"]['navbar']).render(
) menu = globalvar.menu['public']['navbar'],
user_roles = user['profile']['roles'],
active_page = active_page
),
footer = Template(params["mako"]["website"]['footer']).render(
copyright = globalvar.copyright,
),
container = Template(params["mako"]["website"]['container']).render()
)

View File

@ -0,0 +1,6 @@
<h2>Forgot Password</h2>
<p>Please visit this link below to reset password. <b>Avoid the link if you are not request this.</b> </p>
<a href="${reset}" class="button">
Reset password
</a>

View File

@ -0,0 +1,15 @@
<h1>Forgot Password</h1>
<script type="text/javascript" src="/js/carrack.js"></script>
<!-- FORM -->
<input required type="email" id="form-email" placeholder="Email"> <br>
<button onclick="onSubmit()">Submit</button>
<!-- RESPONSE -->
<div id="alert-response" role="alert">
<b id="alert-status">Loading...</b> <span id="alert-desc">Please wait...</span>
</div>
<script type="text/javascript" src="/js/auth/forgot.js"></script>

View File

@ -1 +1,7 @@
<p>${greeting}</p> <p>${greeting}</p>
<p>
<b>Username:</b> ${user['profile']['username']} <br>
<b>Email:</b> ${user['profile']['email']} <br>
<b>Phone:</b> ${user['profile']['phone']} <br>
<b>Roles:</b> ${str(user['profile']['roles'])} <br>
</p>

View File

@ -4,7 +4,9 @@
<input required type="text" id="form-username" placeholder="Username" > <br> <input required type="text" id="form-username" placeholder="Username" > <br>
<input required type="password" id="form-password" placeholder="Password" > <br> <input required type="password" id="form-password" placeholder="Password" > <br>
<button type="button" onclick="onSubmit()">Login</button> <button type="button" onclick="onSubmit()">Login</button> <br>
<a href="/forgot">Forgot password</a>
<div id="alert-response" role="alert"> <div id="alert-response" role="alert">
<b id="alert-status">Loading...</b> <span id="alert-desc">Please wait...</span> <b id="alert-status">Loading...</b> <span id="alert-desc">Please wait...</span>

View File

@ -0,0 +1,16 @@
<h1>Reset Password</h1>
<script type="text/javascript" src="/js/carrack.js"></script>
<!-- FORM -->
<div id="form">
<input required type="password" id="form-password" placeholder="New Password"> <br>
<button onclick="onSubmit()">Submit</button>
</div>
<!-- RESPONSE -->
<div id="alert-response" role="alert">
<b id="alert-status">Loading...</b> <span id="alert-desc">Please wait...</span>
</div>
<script type="text/javascript" src="/js/auth/reset.js"></script>

100
app/procedure/session.py Normal file
View File

@ -0,0 +1,100 @@
import mysql.connector as mariadb
import datetime
import config.database as database
import config.globalvar as globalvar
import scripts.loggorilla as loggorilla
import scripts.tokenguard as tokenguard
class session():
def __init__(self):
self.db_main = mariadb.connect(**database.db_main)
self.cursor = self.db_main.cursor(dictionary=True)
def user(self, jwt, allowed_roles):
APIADDR = "procedure.validation"
response = {}
try:
loggorilla.prcss(APIADDR, "Define parameters")
payload = tokenguard.decode(jwt, globalvar.ssh['key']['public'])
loggorilla.prcss(APIADDR, "Get dependency data")
self.cursor.execute(f"SELECT * FROM auth_session WHERE id = %s ; ", (payload["session"]["id"],) )
r_session = self.cursor.fetchone()
self.cursor.execute(f"SELECT COUNT(*) AS `count`, auth_profile.* FROM auth_profile_verification LEFT JOIN auth_profile ON auth_profile.id = auth_profile_verification.auth_profile WHERE auth_profile.token = %s AND auth_profile_verification.type = 'email' AND auth_profile_verification.verified = 1 ; ", (r_session['token'],) )
r_profile = self.cursor.fetchone()
self.cursor.execute(f"SELECT auth_roles FROM auth_profile_roles WHERE auth_profile = %s ; ", (r_profile['id'],) )
r_roles = self.cursor.fetchall()
r_profile['roles'] = [0]
for row in r_roles:
r_profile['roles'].remove(0)
r_profile['roles'].append(row['auth_roles'])
loggorilla.prcss(APIADDR, "Validation")
if datetime.datetime.now() > r_session['end']:
loggorilla.prcss(APIADDR, "Deleting")
self.cursor.execute("DELETE FROM auth_session WHERE id = %s ; ", (r_session['id'],) )
loggorilla.prcss(APIADDR, "Giving response")
loggorilla.accss(APIADDR, "Expired. Your session removed." )
response["status" ] = "failed"
response["desc" ] = "Expired. Your session removed."
response["data" ] = {
"valid" :{
"status" : 0,
"desc" : "expired"
},
"session" : r_session,
"profile" : r_profile
}
elif r_profile["count"] == 0:
loggorilla.prcss(APIADDR, "Giving response")
loggorilla.accss(APIADDR, "No active account for this" )
response["status" ] = "failed"
response["desc" ] = "No active account for this"
response["data" ] = {
"message" : "Please contact us if you still had a problem",
"valid" :{
"status" : 0,
"desc" : "forbidden"
},
"session" : r_session,
"profile" : r_profile
}
elif any(role in allowed_roles for role in r_profile['roles']):
loggorilla.prcss(APIADDR, "Giving response")
response["status" ] = "success"
response["desc" ] = "User roles authorized"
response["data" ] = {
"valid" :{
"status" : 1,
"desc" : "authorized"
},
"session" : r_session,
"profile" : r_profile
}
else:
loggorilla.prcss(APIADDR, "Giving response")
loggorilla.accss(APIADDR, "User roles unauthorized" )
response["status" ] = "failed"
response["desc" ] = "User roles unauthorized"
response["data" ] = {
"valid" :{
"status" : 0,
"desc" : "unauthorized"
},
"session" : r_session,
"profile" : r_profile
}
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

View File

@ -0,0 +1,42 @@
function flushResponse() {
document.getElementById("alert-response" ).style.display = 'none';
document.getElementById("alert-response" ).classList.remove('alert-success' );
document.getElementById("alert-response" ).classList.remove('alert-danger' );
document.getElementById("alert-response" ).classList.remove('alert-primary' );
}
function loadingResponse() {
flushResponse();
document.getElementById("alert-status" ).innerHTML = "Loading...";
document.getElementById("alert-desc" ).innerHTML = "Please wait...";
document.getElementById("alert-response").classList.add('alert-primary');
document.getElementById("alert-response").style.display = 'block';
}
function responseAlert(response) {
flushResponse();
const obj = JSON.parse(response);
if (obj.status == "success" ) document.getElementById("alert-response").classList.add('alert-success' );
if (obj.status == "failed" ) document.getElementById("alert-response").classList.add('alert-danger' );
document.getElementById("alert-status" ).innerHTML = obj.status;
document.getElementById("alert-desc" ).innerHTML = obj.desc;
document.getElementById("alert-response").style.display = 'block';
}
function onSubmit() {
loadingResponse();
var email = document.getElementById("form-email" ).value;
var url = "/api/auth/password/forgot/send";
var payload = {
"email" : email
};
sendHttpRequest(url, "POST", payload, function (error, response) {
if (error) console.error("Error:", error);
else {
console.log("JSON Response:", response);
responseAlert(response);
}
}, "application/json");
}
flushResponse();

View File

@ -0,0 +1,49 @@
function flushResponse() {
document.getElementById("alert-response" ).style.display = 'none';
document.getElementById("alert-response" ).classList.remove('alert-success' );
document.getElementById("alert-response" ).classList.remove('alert-danger' );
document.getElementById("alert-response" ).classList.remove('alert-primary' );
}
function loadingResponse() {
flushResponse();
document.getElementById("alert-status" ).innerHTML = "Loading...";
document.getElementById("alert-desc" ).innerHTML = "Please wait...";
document.getElementById("alert-response").classList.add('alert-primary');
document.getElementById("alert-response").style.display = 'block';
}
function responseAlert(response) {
flushResponse();
const obj = JSON.parse(response);
if (obj.status == "success" ) {
document.getElementById("form").style.display = 'none';
document.getElementById("alert-response").classList.add('alert-success' );
}
if (obj.status == "failed" ) document.getElementById("alert-response").classList.add('alert-danger' );
document.getElementById("alert-status" ).innerHTML = obj.status;
document.getElementById("alert-desc" ).innerHTML = obj.desc;
document.getElementById("alert-response").style.display = 'block';
}
function onSubmit() {
loadingResponse();
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const token = urlParams.get('token')
var password = document.getElementById("form-password").value;
var url = "/api/auth/password/forgot/change";
var payload = {
"token" : token,
"password" : password
};
sendHttpRequest(url, "POST", payload, function (error, response) {
if (error) console.error("Error:", error);
else {
console.log("JSON Response:", response);
responseAlert(response);
}
}, "application/json");
}
flushResponse();

View File

@ -7,6 +7,13 @@
from core import html from core import html
static = [
{
"route" : "/templates/plain/css/<filepath:re:.*\.(css|sass|css.map)>",
"root" : "./templates/plain/static/css"
}
]
def main(dir, page): def main(dir, page):
html_template = html.main.get_html("templates/plain/html") html_template = html.main.get_html("templates/plain/html")
html_page = html.main.get_html(dir) html_page = html.main.get_html(dir)