diff --git a/.env-template b/.env-template index 4c08222..98f86f3 100644 --- a/.env-template +++ b/.env-template @@ -13,6 +13,8 @@ NGINX_ODOO_SMTP_USER=helpdesk@sunflowerweb.nl NGINX_ODOO_SMTP_PASS=test NGINX_ODOO_LISTEN_HOST=localhost NGINX_ODOO_LISTEN_PORT=8888 +NGINX_ODOO_DEFAULT_LOGIN=./templates/login-2.html +NGINX_ODOO_DEFAULT_HOTP=./templates/hotp-2.html NGINX_ODOO_ODOO_URL=http://localhost:8069 NGINX_ODOO_ODOO_DATABASE=bladatabase # Whether to display the HOTP code in the logs diff --git a/lib/config.py b/lib/config.py index 34e8537..07c17b5 100644 --- a/lib/config.py +++ b/lib/config.py @@ -88,6 +88,8 @@ BUTTONCOLOR = os.environ.get("NGINX_ODOO_BUTTON_COLOR", "") BUTTONHOVERCOLOR = os.environ.get("NGINX_ODOO_BUTTON_HOVER_COLOR", "") BUTTONSHADOWCOLOR = os.environ.get("NGINX_ODOO_BUTTON_SHADOW_COLOR", "") +DEFAULT_LOGIN = os.environ.get("NGINX_ODOO_DEFAULT_LOGIN", r"./templates/login-2.html") +DEFAULT_HOTP = os.environ.get("NGINX_ODOO_DEFAULT_HOTP", r"./templates/hotp-2.html") theme_params = { "backgroundcolor": BACKGROUNDCOLOR, diff --git a/nginx-odoo.py b/nginx-odoo.py index 0e7684c..cc8a2a0 100644 --- a/nginx-odoo.py +++ b/nginx-odoo.py @@ -20,6 +20,8 @@ db = config.db OdooAuthHandler = config.OdooAuthHandler +login_page = config.DEFAULT_LOGIN or r"./templates/login-2.html" +hotp_page = config.DEFAULT_HOTP or r"./templates/hotp-2.html" from lib.email import email @@ -37,7 +39,7 @@ def get(self): if not redirect_url.endswith("/"): redirect_url += "/" return self.redirect(f"{redirect_url}auth/{session_id}") - self.render(r"./templates/login.html", **config.theme_params) + self.render(login_page, **config.theme_params) async def post(self): # handle username/password @@ -60,12 +62,12 @@ async def post(self): message = "Mail with security code not sent." logging.error(message) return self.render( - r"./templates/login.html", + login_page, **config.theme_params, error=message, ) return self.render( - r"./templates/hotp.html", + config.DEFAULT_HOTP, **config.theme_params, counter=counter, code=code, @@ -76,7 +78,7 @@ async def post(self): message = "Invalid username or password." logging.info(message) return self.render( - r"./templates/login.html", **config.theme_params, error=message + login_page, **config.theme_params, error=message ) # check HOTP @@ -88,13 +90,13 @@ async def post(self): if not hotp.verify(hotp_code, int(counter)): message = "Invalid security code." return self.render( - r"./templates/login.html", **config.theme_params, error=message + login_page, **config.theme_params, error=message ) session_id = db.verify_code_and_expiry(counter, code) if not session_id: message = "Invalid security code (2)." return self.render( - r"./templates/login.html", **config.theme_params, error=message + login_page, **config.theme_params, error=message ) db.save_session(session_id, config.EXPIRY_INTERVAL) logging.info("Setting session cookie: %s", session_id) @@ -245,7 +247,15 @@ async def post(self): debug=True, ) +# Use this after setup instructions if purpose is just testing tornado server +def main(): + # Create an HTTP server listening on localhost, port 8080. + http_server = tornado.httpserver.HTTPServer(app) + http_server.listen(8080, address='127.0.0.1') + tornado.ioloop.IOLoop.current().start() + if __name__ == "__main__": + # main() # Check connection with email service loop = asyncio.get_event_loop() loop.run_until_complete(email.test()) diff --git a/static/hotp-2.css b/static/hotp-2.css new file mode 100644 index 0000000..cf20123 --- /dev/null +++ b/static/hotp-2.css @@ -0,0 +1,18 @@ +html { + /*background: linear-gradient( 90deg, #d2d5d487, #8c929391, #aeb4b58f, #9b97989e, #7e7b7ba1, #a59e9e9e, #938d8ac4, #c7c5c3bf );*/ + /*background: linear-gradient( 90deg, #005c4f87, #005c6091, #0181878f, #ac255e9e, #ca485ca1, #e16b5c9e, #f39060c4, #ffb56bbf );*/ +} + +.container { + margin-top: 200px; + padding: 50px; +} + +.factor-auth-input { + position: relative; + overflow: hidden; + margin: 0px; + color: #333; + background-color: #fff; + border-color: #ccc; +} diff --git a/static/img/user-2.png b/static/img/user-2.png new file mode 100644 index 0000000..71c2b2b Binary files /dev/null and b/static/img/user-2.png differ diff --git a/static/img/user-3.png b/static/img/user-3.png new file mode 100644 index 0000000..ec6c6de Binary files /dev/null and b/static/img/user-3.png differ diff --git a/static/img/user.png b/static/img/user.png new file mode 100644 index 0000000..db51808 Binary files /dev/null and b/static/img/user.png differ diff --git a/static/login-2.css b/static/login-2.css new file mode 100644 index 0000000..39e78e3 --- /dev/null +++ b/static/login-2.css @@ -0,0 +1,262 @@ + +/* BASIC */ + +html { + background-color: #56baed; +} + +body { + font-family: "Poppins", sans-serif; + height: 100vh; +} + +a { + color: #92badd; + display:inline-block; + text-decoration: none; + font-weight: 400; +} + +h2 { + text-align: center; + font-size: 16px; + font-weight: 600; + text-transform: uppercase; + display:inline-block; + margin: 40px 8px 10px 8px; + color: #cccccc; +} + + + +/* STRUCTURE */ + +.wrapper { + display: flex; + align-items: center; + flex-direction: column; + justify-content: center; + width: 100%; + min-height: 100%; + padding: 20px; +} + +#formContent { + -webkit-border-radius: 10px 10px 10px 10px; + border-radius: 10px 10px 10px 10px; + background: #fff; + padding: 30px; + width: 90%; + max-width: 450px; + position: relative; + padding: 0px; + -webkit-box-shadow: 0 30px 60px 0 rgba(0,0,0,0.3); + box-shadow: 0 30px 60px 0 rgba(0,0,0,0.3); + text-align: center; +} + +#formFooter { + background-color: #f6f6f6; + border-top: 1px solid #dce8f1; + padding: 25px; + text-align: center; + -webkit-border-radius: 0 0 10px 10px; + border-radius: 0 0 10px 10px; +} + + + +/* TABS */ + +h2.inactive { + color: #cccccc; +} + +h2.active { + color: #0d0d0d; + border-bottom: 2px solid #5fbae9; +} + + + +/* FORM TYPOGRAPHY*/ + +input[type=button], input[type=submit], input[type=reset] { + background-color: #56baed; + border: none; + color: white; + padding: 15px 80px; + text-align: center; + text-decoration: none; + display: inline-block; + text-transform: uppercase; + font-size: 13px; + -webkit-box-shadow: 0 10px 30px 0 rgba(95,186,233,0.4); + box-shadow: 0 10px 30px 0 rgba(95,186,233,0.4); + -webkit-border-radius: 5px 5px 5px 5px; + border-radius: 5px 5px 5px 5px; + margin: 5px 20px 40px 20px; + -webkit-transition: all 0.3s ease-in-out; + -moz-transition: all 0.3s ease-in-out; + -ms-transition: all 0.3s ease-in-out; + -o-transition: all 0.3s ease-in-out; + transition: all 0.3s ease-in-out; +} + +input[type=button]:hover, input[type=submit]:hover, input[type=reset]:hover { + background-color: #39ace7; +} + +input[type=button]:active, input[type=submit]:active, input[type=reset]:active { + -moz-transform: scale(0.95); + -webkit-transform: scale(0.95); + -o-transform: scale(0.95); + -ms-transform: scale(0.95); + transform: scale(0.95); +} + +input[type=text], input[type=password] { + background-color: #f6f6f6; + border: none; + color: #0d0d0d; + padding: 15px 32px; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 16px; + margin: 5px; + width: 85%; + border: 2px solid #f6f6f6; + -webkit-transition: all 0.5s ease-in-out; + -moz-transition: all 0.5s ease-in-out; + -ms-transition: all 0.5s ease-in-out; + -o-transition: all 0.5s ease-in-out; + transition: all 0.5s ease-in-out; + -webkit-border-radius: 5px 5px 5px 5px; + border-radius: 5px 5px 5px 5px; +} + +input[type=text]:focus, input[type=password]:focus { + background-color: #fff; + border-bottom: 2px solid #5fbae9; +} + +input[type=text]:placeholder, input[type=password]:placeholder { + color: #cccccc; +} + + + +/* ANIMATIONS */ + +/* Simple CSS3 Fade-in-down Animation */ +.fadeInDown { + -webkit-animation-name: fadeInDown; + animation-name: fadeInDown; + -webkit-animation-duration: 1s; + animation-duration: 1s; + -webkit-animation-fill-mode: both; + animation-fill-mode: both; +} + +@-webkit-keyframes fadeInDown { + 0% { + opacity: 0; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + } + 100% { + opacity: 1; + -webkit-transform: none; + transform: none; + } +} + +@keyframes fadeInDown { + 0% { + opacity: 0; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + } + 100% { + opacity: 1; + -webkit-transform: none; + transform: none; + } +} + +/* Simple CSS3 Fade-in Animation */ +@-webkit-keyframes fadeIn { from { opacity:0; } to { opacity:1; } } +@-moz-keyframes fadeIn { from { opacity:0; } to { opacity:1; } } +@keyframes fadeIn { from { opacity:0; } to { opacity:1; } } + +.fadeIn { + opacity:0; + -webkit-animation:fadeIn ease-in 1; + -moz-animation:fadeIn ease-in 1; + animation:fadeIn ease-in 1; + + -webkit-animation-fill-mode:forwards; + -moz-animation-fill-mode:forwards; + animation-fill-mode:forwards; + + -webkit-animation-duration:1s; + -moz-animation-duration:1s; + animation-duration:1s; +} + +.fadeIn.first { + -webkit-animation-delay: 0.4s; + -moz-animation-delay: 0.4s; + animation-delay: 0.4s; +} + +.fadeIn.second { + -webkit-animation-delay: 0.6s; + -moz-animation-delay: 0.6s; + animation-delay: 0.6s; +} + +.fadeIn.third { + -webkit-animation-delay: 0.8s; + -moz-animation-delay: 0.8s; + animation-delay: 0.8s; +} + +.fadeIn.fourth { + -webkit-animation-delay: 1s; + -moz-animation-delay: 1s; + animation-delay: 1s; +} + +/* Simple CSS3 Fade-in Animation */ +.underlineHover:after { + display: block; + left: 0; + bottom: -10px; + width: 0; + height: 2px; + background-color: #56baed; + content: ""; + transition: width 0.2s; +} + +.underlineHover:hover { + color: #0d0d0d; +} + +.underlineHover:hover:after{ + width: 100%; +} + + + +/* OTHERS */ + +*:focus { + outline: none; +} + +#icon { + width: 20%; +} diff --git a/static/login-3.css b/static/login-3.css new file mode 100644 index 0000000..e49f49b --- /dev/null +++ b/static/login-3.css @@ -0,0 +1,75 @@ +.form-signin +{ + max-width: 330px; + padding: 15px; + margin: 0 auto; +} +.form-signin .form-signin-heading, .form-signin .checkbox +{ + margin-bottom: 10px; +} +.form-signin .checkbox +{ + font-weight: normal; +} +.form-signin .form-control +{ + position: relative; + font-size: 16px; + height: auto; + padding: 10px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.form-signin .form-control:focus +{ + z-index: 2; +} +.form-signin input[type="text"] +{ + margin-bottom: -1px; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} +.form-signin input[type="password"] +{ + margin-bottom: 10px; + border-top-left-radius: 0; + border-top-right-radius: 0; +} +.account-wall +{ + margin-top: 20px; + padding: 40px 0px 20px 0px; + background-color: #f7f7f7; + -moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); + -webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); + box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); +} +.login-title +{ + color: #555; + font-size: 18px; + font-weight: 400; + display: block; +} +.profile-img +{ + width: 96px; + height: 96px; + margin: 0 auto 10px; + display: block; + -moz-border-radius: 50%; + -webkit-border-radius: 50%; + border-radius: 50%; +} +.need-help +{ + margin-top: 10px; +} +.new-account +{ + display: block; + margin-top: 10px; +} \ No newline at end of file diff --git a/static/login-4.css b/static/login-4.css new file mode 100644 index 0000000..d6c5217 --- /dev/null +++ b/static/login-4.css @@ -0,0 +1,141 @@ +/* + * Specific styles of signin component + */ +/* + * General styles + */ +body, html { + height: 100%; + background-repeat: no-repeat; + background-image: linear-gradient(rgb(104, 145, 162), rgb(126 241 150)); +} + +.card-container.card { + max-width: 350px; + padding: 40px 40px; +} + +.btn { + font-weight: 700; + height: 36px; + -moz-user-select: none; + -webkit-user-select: none; + user-select: none; + cursor: default; +} + +/* + * Card component + */ +.card { + background-color: #F7F7F7; + /* just in case there no content*/ + padding: 20px 25px 30px; + margin: 0 auto 25px; + margin-top: 50px; + /* shadows and rounded borders */ + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + border-radius: 2px; + -moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); + -webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); + box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3); +} + +.profile-img-card { + width: 96px; + height: 96px; + margin: 0 auto 10px; + display: block; + -moz-border-radius: 50%; + -webkit-border-radius: 50%; + border-radius: 50%; +} + +/* + * Form styles + */ +.profile-name-card { + font-size: 16px; + font-weight: bold; + text-align: center; + margin: 10px 0 0; + min-height: 1em; +} + +.reauth-email { + display: block; + color: #404040; + line-height: 2; + margin-bottom: 10px; + font-size: 14px; + text-align: center; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +.form-signin #inputEmail, +.form-signin #inputPassword { + direction: ltr; + height: 44px; + font-size: 16px; +} + +.form-signin input[type=email], +.form-signin input[type=password], +.form-signin input[type=text], +.form-signin button { + width: 100%; + display: block; + margin-bottom: 10px; + z-index: 1; + position: relative; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +.form-signin .form-control:focus { + border-color: rgb(104, 145, 162); + outline: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgb(104, 145, 162); + box-shadow: inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgb(104, 145, 162); +} + +.btn.btn-signin { + /*background-color: #4d90fe; */ + background-color: rgb(104, 145, 162); + /* background-color: linear-gradient(rgb(104, 145, 162), rgb(12, 97, 33));*/ + padding: 0px; + font-weight: 700; + font-size: 14px; + height: 36px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + border-radius: 3px; + border: none; + -o-transition: all 0.218s; + -moz-transition: all 0.218s; + -webkit-transition: all 0.218s; + transition: all 0.218s; +} + +.btn.btn-signin:hover, +.btn.btn-signin:active, +.btn.btn-signin:focus { + background-color: rgb(12, 97, 33); +} + +.forgot-password { + color: rgb(104, 145, 162); +} + +.forgot-password:hover, +.forgot-password:active, +.forgot-password:focus{ + color: rgb(12, 97, 33); +} \ No newline at end of file diff --git a/static/login-5.css b/static/login-5.css new file mode 100644 index 0000000..eccd269 --- /dev/null +++ b/static/login-5.css @@ -0,0 +1,67 @@ +/* Coded with love by Mutiullah Samim */ + body, html { + margin: 0; + padding: 0; + height: 100%; + background: #fff !important; +} + .user_card { + height: 400px; + width: 350px; + margin-top: auto; + margin-bottom: auto; + background: #bec4c5; + position: relative; + display: flex; + justify-content: center; + flex-direction: column; + padding: 10px; + box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); + -webkit-box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); + -moz-box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); + border-radius: 5px; +} + .brand_logo_container { + position: absolute; + height: 170px; + width: 170px; + top: -75px; + border-radius: 50%; + background: #60a3bc; + padding: 10px; + text-align: center; +} + .brand_logo { + height: 150px; + width: 150px; + border-radius: 50%; + border: 2px solid white; +} + .form_container { + margin-top: 100px; +} + .login_btn { + width: 100%; + background: #c0392b !important; + color: white !important; +} + .login_btn:focus { + box-shadow: none !important; + outline: 0px !important; +} + .login_container { + padding: 0 2rem; +} + .input-group-text { + background: #c0392b !important; + color: white !important; + border: 0 !important; + border-radius: 0.25rem 0 0 0.25rem !important; +} + .input_user, .input_pass:focus { + box-shadow: none !important; + outline: 0px !important; +} + .custom-checkbox .custom-control-input:checked~.custom-control-label::before { + background-color: #c0392b !important; +} diff --git a/templates/hotp-2.html b/templates/hotp-2.html new file mode 100644 index 0000000..b4a696a --- /dev/null +++ b/templates/hotp-2.html @@ -0,0 +1,58 @@ + + +
+ + + + + + {% if 'branding' in vars() %} + +
+