
18 changed files with 571 additions and 67 deletions
@ -1,3 +1,40 @@ |
|||||||
|
.alert a { |
||||||
|
color:inherit; |
||||||
|
font-weight:bold; |
||||||
|
} |
||||||
|
|
||||||
.o3-login-card { |
.o3-login-card { |
||||||
margin-top:7em; |
margin-top:7em; |
||||||
} |
} |
||||||
|
|
||||||
|
|
||||||
|
.o3-registration-card { |
||||||
|
margin-top:1em; |
||||||
|
margin-bottom:2em; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
.o3-registration-card .alert-danger { |
||||||
|
font-size: 80%; |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
|
||||||
|
.o3-registration-card .help-block { |
||||||
|
color: #6c757d!important; |
||||||
|
font-size: 80%; |
||||||
|
font-weight: 400; |
||||||
|
display: block; |
||||||
|
margin-top: .25rem; |
||||||
|
} |
||||||
|
|
||||||
|
.o3-pwd-dots .bi-eye-slash, .o3-pwd-text .bi-eye { |
||||||
|
display:inline; |
||||||
|
} |
||||||
|
|
||||||
|
.o3-pwd-dots .bi-eye, .o3-pwd-text .bi-eye-slash { |
||||||
|
display:none; |
||||||
|
} |
||||||
|
|
||||||
|
.form-group.deform-form-buttons { |
||||||
|
margin-top:2em; |
||||||
|
} |
||||||
|
@ -0,0 +1,51 @@ |
|||||||
|
{% extends "ordr3:templates/layout_small.jinja2" %} |
||||||
|
|
||||||
|
{% block subtitle %} Log In {% endblock subtitle %} |
||||||
|
|
||||||
|
{% block content %} |
||||||
|
|
||||||
|
<div class="container"> |
||||||
|
<div class="row o3-registration-card"> |
||||||
|
<div class="col"></div> |
||||||
|
<div class="col"> |
||||||
|
<div class="card"> |
||||||
|
<div class="card-header bg-dark text-light"> |
||||||
|
<h2 class="card-title text-center pt-1">Ordr</h5> |
||||||
|
</div> |
||||||
|
<div class="card-body"> |
||||||
|
<h6>Why is Ordr telling me my password is compromised?</h6> |
||||||
|
<p> |
||||||
|
Ordr itself has not suffered a breach. This is a protective measure to |
||||||
|
reduce the risk of <a href="https://www.owasp.org/index.php/Credential_stuffing" target="_blank" rel="noopener">credential stuffing</a> |
||||||
|
attacks against Ordr and its users. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
Each time a user supplies a password while registering or updating their |
||||||
|
password — Ordr securely checks whether that password has appeared in |
||||||
|
public data breaches. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
During each of these processes, Ordr generates a SHA-1 hash of the |
||||||
|
supplied password and uses the first five (5) characters of the hash to |
||||||
|
check the <a href="https://haveibeenpwned.com/API/v2#SearchingPwnedPasswordsByRange" target="_blank" rel="noopener">Have I Been Pwned API</a> |
||||||
|
and determine if the password has been previously compromised. |
||||||
|
The plaintext password is never stored by Ordr or submitted to the |
||||||
|
Have I Been Pwned API. |
||||||
|
</p> |
||||||
|
<p> |
||||||
|
If you receive an error message saying that |
||||||
|
"This password appears in a breach or has been compromised.", |
||||||
|
you should change it all other places that you use it as soon as possible. |
||||||
|
</p> |
||||||
|
<p class="small text-secondary"> |
||||||
|
This text originally appeared on the <a href="https://pypi.org/help/#compromised-password" target="_blank" rel="noopener">PyPI FAQ</a>. |
||||||
|
<p> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="col"></div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
|
||||||
|
{% endblock content %} |
@ -0,0 +1,25 @@ |
|||||||
|
{% extends "ordr3:templates/layout_small.jinja2" %} |
||||||
|
|
||||||
|
{% block subtitle %} Registration {% endblock subtitle %} |
||||||
|
|
||||||
|
{% block content %} |
||||||
|
|
||||||
|
<div class="container"> |
||||||
|
<div class="row o3-registration-card"> |
||||||
|
<div class="col"></div> |
||||||
|
<div class="col"> |
||||||
|
<div class="card"> |
||||||
|
<div class="card-header bg-dark text-light"> |
||||||
|
<h2 class="card-title text-center pt-1">Ordr</h5> |
||||||
|
</div> |
||||||
|
<div class="card-body"> |
||||||
|
<h6 class="card-subtitle mb-2 text-muted text-center mt-1 mb-4">Register a new account</h6> |
||||||
|
{{form.render()|safe}} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="col"></div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
{% endblock content %} |
@ -0,0 +1,34 @@ |
|||||||
|
{% extends "ordr3:templates/layout_small.jinja2" %} |
||||||
|
|
||||||
|
{% block subtitle %} Registration completed {% endblock subtitle %} |
||||||
|
|
||||||
|
{% block content %} |
||||||
|
|
||||||
|
<div class="container"> |
||||||
|
<div class="row o3-registration-card"> |
||||||
|
<div class="col"></div> |
||||||
|
<div class="col"> |
||||||
|
<div class="card"> |
||||||
|
<div class="card-header bg-dark text-light"> |
||||||
|
<h2 class="card-title text-center pt-1">Ordr</h5> |
||||||
|
</div> |
||||||
|
<div class="card-body"> |
||||||
|
<h6 class="card-subtitle mb-2 text-muted text-center mt-1 mb-4">Registration completed</h6> |
||||||
|
{% for message in request.session.pop_flash("warning") %} |
||||||
|
<div class="alert alert-warning" role="alert"> |
||||||
|
<p class="h6">{{message[0]}}</p> |
||||||
|
<p class="small">{{message[1]|safe}}</p> |
||||||
|
</div> |
||||||
|
{% endfor %} |
||||||
|
|
||||||
|
<p>The registration is completed.<p> |
||||||
|
<p>The account needs to be activated by an administrator.</p> |
||||||
|
<p>You should receive an email as soon as the account is activated.</p> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="col"></div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
{% endblock content %} |
@ -0,0 +1,23 @@ |
|||||||
|
<span tal:define="name name|field.name; |
||||||
|
css_class css_class|field.widget.css_class; |
||||||
|
oid oid|field.oid; |
||||||
|
mask mask|field.widget.mask; |
||||||
|
mask_placeholder mask_placeholder|field.widget.mask_placeholder; |
||||||
|
style style|field.widget.style; |
||||||
|
" |
||||||
|
tal:omit-tag=""> |
||||||
|
<input type="email" name="${name}" value="${cstruct}" |
||||||
|
tal:attributes="required string: ${required|'required' or ''}; |
||||||
|
class string: form-control ${css_class or ''} ${'is-invalid' if field.error else ''}; |
||||||
|
style style; |
||||||
|
attributes|field.widget.attributes|{};" |
||||||
|
id="${oid}"/> |
||||||
|
<script tal:condition="mask" type="text/javascript"> |
||||||
|
deform.addCallback( |
||||||
|
'${oid}', |
||||||
|
function (oid) { |
||||||
|
$("#" + oid).mask("${mask}", |
||||||
|
{placeholder:"${mask_placeholder}"}); |
||||||
|
}); |
||||||
|
</script> |
||||||
|
</span> |
@ -0,0 +1,109 @@ |
|||||||
|
<form |
||||||
|
tal:define="style style|field.widget.style; |
||||||
|
css_class css_class|string:${field.widget.css_class or field.css_class or ''}; |
||||||
|
item_template item_template|field.widget.item_template; |
||||||
|
autocomplete autocomplete|field.autocomplete; |
||||||
|
title title|field.title; |
||||||
|
errormsg errormsg|field.errormsg; |
||||||
|
description description|field.description; |
||||||
|
buttons buttons|field.buttons; |
||||||
|
use_ajax use_ajax|field.use_ajax; |
||||||
|
ajax_options ajax_options|field.ajax_options; |
||||||
|
formid formid|field.formid; |
||||||
|
action action|field.action or None; |
||||||
|
method method|field.method;" |
||||||
|
tal:attributes="autocomplete autocomplete; |
||||||
|
style style; |
||||||
|
class css_class; |
||||||
|
action action; |
||||||
|
attributes|field.widget.attributes|{};" |
||||||
|
id="${formid}" |
||||||
|
method="${method}" |
||||||
|
enctype="multipart/form-data" |
||||||
|
accept-charset="utf-8" |
||||||
|
i18n:domain="deform" |
||||||
|
> |
||||||
|
|
||||||
|
<fieldset class="deform-form-fieldset"> |
||||||
|
|
||||||
|
<legend tal:condition="title">${title}</legend> |
||||||
|
|
||||||
|
<input type="hidden" name="_charset_" /> |
||||||
|
<input type="hidden" name="__formid__" value="${formid}"/> |
||||||
|
|
||||||
|
<div class="alert alert-danger" tal:condition="field.error"> |
||||||
|
<div class="error-msg-lbl" i18n:translate="" |
||||||
|
>There was a problem with your submission</div> |
||||||
|
<div class="error-msg-detail" i18n:translate="" |
||||||
|
>Errors have been highlighted below</div> |
||||||
|
<p class="error-msg" tal:condition="field.errormsg">${field.errormsg}</p> |
||||||
|
</div> |
||||||
|
|
||||||
|
<p class="section first" tal:condition="description"> |
||||||
|
${description} |
||||||
|
</p> |
||||||
|
|
||||||
|
<div tal:repeat="child field" |
||||||
|
tal:replace="structure child.render_template(item_template)"/> |
||||||
|
|
||||||
|
<div class="form-group deform-form-buttons"> |
||||||
|
<tal:loop tal:repeat="button buttons"> |
||||||
|
<button |
||||||
|
tal:define="btn_disposition repeat.button.start and 'btn-primary' or 'btn-outline-secondary';" |
||||||
|
tal:attributes="disabled button.disabled if button.disabled else None; |
||||||
|
attributes|button.attributes|{};" |
||||||
|
id="${formid+button.name}" |
||||||
|
name="${button.name}" |
||||||
|
type="${button.type}" |
||||||
|
class="btn ${button.css_class or btn_disposition}" |
||||||
|
value="${button.value}" |
||||||
|
tal:condition="button.type != 'link'"> |
||||||
|
<span tal:condition="button.icon" class="glyphicon glyphicon-${button.icon}"></span> |
||||||
|
${button.title} |
||||||
|
</button> |
||||||
|
<a |
||||||
|
tal:define="btn_disposition repeat.button.start and 'btn-primary' or 'btn-outline-secondary'; |
||||||
|
btn_href button.value|''" |
||||||
|
class="btn ${button.css_class or btn_disposition}" |
||||||
|
id="${field.formid + button.name}" |
||||||
|
href="${btn_href}" |
||||||
|
tal:condition="button.type == 'link'"> |
||||||
|
<span tal:condition="button.icon" class="glyphicon glyphicon-${button.icon}"></span> |
||||||
|
${button.title} |
||||||
|
</a> |
||||||
|
</tal:loop> |
||||||
|
</div> |
||||||
|
|
||||||
|
</fieldset> |
||||||
|
|
||||||
|
<script type="text/javascript" tal:condition="use_ajax"> |
||||||
|
deform.addCallback( |
||||||
|
'${formid}', |
||||||
|
function(oid) { |
||||||
|
var target = '#' + oid; |
||||||
|
var options = { |
||||||
|
target: target, |
||||||
|
replaceTarget: true, |
||||||
|
success: function() { |
||||||
|
deform.processCallbacks(); |
||||||
|
deform.focusFirstInput(target); |
||||||
|
}, |
||||||
|
beforeSerialize: function() { |
||||||
|
// See http://bit.ly/1agBs9Z (hack to fix tinymce-related ajax bug) |
||||||
|
if ('tinymce' in window) { |
||||||
|
$(tinymce.get()).each( |
||||||
|
function(i, el) { |
||||||
|
var content = el.getContent(); |
||||||
|
var editor_input = document.getElementById(el.id); |
||||||
|
editor_input.value = content; |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
var extra_options = ${ajax_options} || {}; |
||||||
|
$('#' + oid).ajaxForm($.extend(options, extra_options)); |
||||||
|
} |
||||||
|
); |
||||||
|
</script> |
||||||
|
|
||||||
|
</form> |
@ -0,0 +1,3 @@ |
|||||||
|
<input type="hidden" name="${name|field.name}" value="${cstruct}" |
||||||
|
id="${oid|field.oid}"/> |
||||||
|
|
@ -0,0 +1,48 @@ |
|||||||
|
<div tal:define="error_class error_class|field.widget.error_class; |
||||||
|
description description|field.description; |
||||||
|
title title|field.title; |
||||||
|
oid oid|field.oid; |
||||||
|
hidden hidden|field.widget.hidden; |
||||||
|
category category|field.widget.category; |
||||||
|
structural hidden or category == 'structural'; |
||||||
|
required required|field.required;" |
||||||
|
class="form-group ${field.error and 'has-error' or ''} ${field.widget.item_css_class or ''} ${field.default_item_css_class()}" |
||||||
|
title="${description}" |
||||||
|
id="item-${oid}" |
||||||
|
tal:omit-tag="structural" |
||||||
|
i18n:domain="deform"> |
||||||
|
|
||||||
|
<label for="${oid}" |
||||||
|
class="control-label ${required and 'required' or ''}" |
||||||
|
tal:condition="not structural" |
||||||
|
id="req-${oid}" |
||||||
|
> |
||||||
|
${title} |
||||||
|
</label> |
||||||
|
|
||||||
|
<div tal:define="input_prepend field.widget.input_prepend | None; |
||||||
|
input_append field.widget.input_append | None" |
||||||
|
tal:omit-tag="not (input_prepend or input_append)" |
||||||
|
class="input-group"> |
||||||
|
<span class="input-group-addon" |
||||||
|
tal:condition="input_prepend">${input_prepend}</span |
||||||
|
><span tal:replace="structure field.serialize(cstruct).strip()" |
||||||
|
/><span class="input-group-addon" |
||||||
|
tal:condition="input_append">${input_append}</span> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="invalid-feedback" |
||||||
|
tal:define="errstr 'error-%s' % field.oid" |
||||||
|
tal:repeat="msg field.error.messages()" |
||||||
|
i18n:translate="" |
||||||
|
tal:attributes="id repeat.msg.index==0 and errstr or |
||||||
|
('%s-%s' % (errstr, repeat.msg.index))" |
||||||
|
tal:condition="field.error and not field.widget.hidden and not field.typ.__class__.__name__=='Mapping'"> |
||||||
|
${msg} |
||||||
|
</div> |
||||||
|
|
||||||
|
<p tal:condition="field.description and not field.widget.hidden" |
||||||
|
class="help-block" > |
||||||
|
${field.description} |
||||||
|
</p> |
||||||
|
</div> |
@ -0,0 +1,23 @@ |
|||||||
|
<span tal:define="name name|field.name; |
||||||
|
css_class css_class|field.widget.css_class; |
||||||
|
oid oid|field.oid; |
||||||
|
mask mask|field.widget.mask; |
||||||
|
mask_placeholder mask_placeholder|field.widget.mask_placeholder; |
||||||
|
style style|field.widget.style; |
||||||
|
" |
||||||
|
tal:omit-tag=""> |
||||||
|
<input type="text" name="${name}" value="${cstruct}" |
||||||
|
tal:attributes="required string: ${required|'required' or ''}; |
||||||
|
class string: form-control ${css_class or ''} ${'is-invalid' if field.error else ''} |
||||||
|
style style; |
||||||
|
attributes|field.widget.attributes|{};" |
||||||
|
id="${oid}"/> |
||||||
|
<script tal:condition="mask" type="text/javascript"> |
||||||
|
deform.addCallback( |
||||||
|
'${oid}', |
||||||
|
function (oid) { |
||||||
|
$("#" + oid).mask("${mask}", |
||||||
|
{placeholder:"${mask_placeholder}"}); |
||||||
|
}); |
||||||
|
</script> |
||||||
|
</span> |
@ -0,0 +1,22 @@ |
|||||||
|
<span tal:define="name name|field.name; |
||||||
|
css_class css_class|field.widget.css_class; |
||||||
|
oid oid|field.oid; |
||||||
|
mask mask|field.widget.mask|None; |
||||||
|
mask_placeholder mask_placeholder|field.widget.mask_placeholder|'_'; |
||||||
|
style style|field.widget.style; |
||||||
|
" |
||||||
|
tal:omit-tag=""> |
||||||
|
<input type="text" name="${name}" value="${cstruct}" |
||||||
|
tal:attributes="class string: form-control ${css_class or ''} ${'is-invalid' if field.error else ''} |
||||||
|
style style" |
||||||
|
id="${oid}" |
||||||
|
readonly="readonly"/> |
||||||
|
<script tal:condition="mask" type="text/javascript"> |
||||||
|
deform.addCallback( |
||||||
|
'${oid}', |
||||||
|
function (oid) { |
||||||
|
$("#" + oid).mask("${mask}", |
||||||
|
{placeholder:"${mask_placeholder}"}); |
||||||
|
}); |
||||||
|
</script> |
||||||
|
</span> |
@ -0,0 +1,29 @@ |
|||||||
|
<div class="input-group"> |
||||||
|
<input |
||||||
|
type="password" |
||||||
|
name="${name|field.name}" |
||||||
|
value="${field.widget.redisplay and cstruct or ''}" |
||||||
|
tal:attributes="required string: ${required|'required' or ''}; |
||||||
|
style style|field.widget.style; |
||||||
|
class string: form-control o3-pwd-field ${css_class|field.widget.css_class or ''} ${'is-invalid' if field.error else ''}; |
||||||
|
attributes|field.widget.attributes|{}; |
||||||
|
" |
||||||
|
id="${oid|field.oid}" |
||||||
|
|
||||||
|
/> |
||||||
|
<div class="input-group-append o3-pwd-visibility o3-pwd-dots"> |
||||||
|
<div class="input-group-text"> |
||||||
|
<svg class="bi bi-eye" width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> |
||||||
|
<path fill-rule="evenodd" d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.134 13.134 0 001.66 2.043C4.12 11.332 5.88 12.5 8 12.5c2.12 0 3.879-1.168 5.168-2.457A13.134 13.134 0 0014.828 8a13.133 13.133 0 00-1.66-2.043C11.879 4.668 10.119 3.5 8 3.5c-2.12 0-3.879 1.168-5.168 2.457A13.133 13.133 0 001.172 8z" clip-rule="evenodd"/> |
||||||
|
<path fill-rule="evenodd" d="M8 5.5a2.5 2.5 0 100 5 2.5 2.5 0 000-5zM4.5 8a3.5 3.5 0 117 0 3.5 3.5 0 01-7 0z" clip-rule="evenodd"/> |
||||||
|
</svg> |
||||||
|
<svg class="bi bi-eye-slash" width="1em" height="1em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> |
||||||
|
<path d="M13.359 11.238C15.06 9.72 16 8 16 8s-3-5.5-8-5.5a7.028 7.028 0 00-2.79.588l.77.771A5.944 5.944 0 018 3.5c2.12 0 3.879 1.168 5.168 2.457A13.134 13.134 0 0114.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755-.165.165-.337.328-.517.486l.708.709z"/> |
||||||
|
<path d="M11.297 9.176a3.5 3.5 0 00-4.474-4.474l.823.823a2.5 2.5 0 012.829 2.829l.822.822zm-2.943 1.299l.822.822a3.5 3.5 0 01-4.474-4.474l.823.823a2.5 2.5 0 002.829 2.829z"/> |
||||||
|
<path d="M3.35 5.47c-.18.16-.353.322-.518.487A13.134 13.134 0 001.172 8l.195.288c.335.48.83 1.12 1.465 1.755C4.121 11.332 5.881 12.5 8 12.5c.716 0 1.39-.133 2.02-.36l.77.772A7.029 7.029 0 018 13.5C3 13.5 0 8 0 8s.939-1.721 2.641-3.238l.708.709z"/> |
||||||
|
<path fill-rule="evenodd" d="M13.646 14.354l-12-12 .708-.708 12 12-.708.708z" clip-rule="evenodd"/> |
||||||
|
</svg> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
</div> |
@ -0,0 +1,25 @@ |
|||||||
|
<!DOCTYPE html> |
||||||
|
<html lang="en"> |
||||||
|
<head> |
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> |
||||||
|
|
||||||
|
<title>Ordr | {% block subtitle %} Subtitle {% endblock subtitle %}</title> |
||||||
|
|
||||||
|
<link href="{{request.static_url('ordr3:static/favicon.ico')}}" type="image/x-icon" rel="shortcut icon"> |
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous"> |
||||||
|
<link rel="stylesheet" href="{{request.static_url('ordr3:static/style.css')}}" type="text/css" media="screen" /> |
||||||
|
|
||||||
|
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script> |
||||||
|
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script> |
||||||
|
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script> |
||||||
|
<script src="{{request.static_url('ordr3:static/script.js')}}"></script> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
|
||||||
|
{% block content %} |
||||||
|
<p>No content</p> |
||||||
|
{% endblock content %} |
||||||
|
|
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,123 @@ |
|||||||
|
""" static and login pages """ |
||||||
|
|
||||||
|
|
||||||
|
import deform |
||||||
|
from pyramid.view import view_config |
||||||
|
from pyramid.security import forget, remember |
||||||
|
from pyramid.httpexceptions import HTTPFound |
||||||
|
|
||||||
|
from .. import models, security, services |
||||||
|
from ..schemas.account import RegistrationSchema |
||||||
|
|
||||||
|
|
||||||
|
@view_config( |
||||||
|
context="ordr3:resources.Root", |
||||||
|
name="login", |
||||||
|
permission="login", |
||||||
|
request_method="GET", |
||||||
|
renderer="ordr3:templates/account/login.jinja2", |
||||||
|
) |
||||||
|
def login(context, request): |
||||||
|
return {"error": False} |
||||||
|
|
||||||
|
|
||||||
|
@view_config( |
||||||
|
context="ordr3:resources.Root", |
||||||
|
name="login", |
||||||
|
permission="login", |
||||||
|
request_method="POST", |
||||||
|
require_csrf=False, |
||||||
|
renderer="ordr3:templates/account/login.jinja2", |
||||||
|
) |
||||||
|
def check_credentials(context, request): |
||||||
|
username = request.POST.get("username", "") |
||||||
|
password = request.POST.get("password", "") |
||||||
|
|
||||||
|
crypt_context = security.get_passlib_context() |
||||||
|
user = services.verify_credentials( |
||||||
|
request.repo, crypt_context, username, password |
||||||
|
) |
||||||
|
if user is not None and user.is_active: |
||||||
|
headers = remember(request, user.id) |
||||||
|
return HTTPFound( |
||||||
|
request.resource_path(request.root, "orders"), headers=headers |
||||||
|
) |
||||||
|
return {"error": True} |
||||||
|
|
||||||
|
|
||||||
|
@view_config( |
||||||
|
context="ordr3:resources.Root", name="logout", permission="logout" |
||||||
|
) |
||||||
|
def logout(context, request): |
||||||
|
""" logout of a user """ |
||||||
|
return HTTPFound( |
||||||
|
request.resource_path(request.root, "login"), headers=forget(request) |
||||||
|
) |
||||||
|
|
||||||
|
|
||||||
|
@view_config( |
||||||
|
context="ordr3:resources.Root", |
||||||
|
name="registration", |
||||||
|
permission="registration", |
||||||
|
request_method="GET", |
||||||
|
renderer="ordr3:templates/account/registration.jinja2", |
||||||
|
) |
||||||
|
def registration(context, request): |
||||||
|
form = RegistrationSchema.as_form(request) |
||||||
|
return {"form": form} |
||||||
|
|
||||||
|
|
||||||
|
@view_config( |
||||||
|
context="ordr3:resources.Root", |
||||||
|
name="registration", |
||||||
|
permission="registration", |
||||||
|
request_method="POST", |
||||||
|
renderer="ordr3:templates/account/registration.jinja2", |
||||||
|
) |
||||||
|
def register_new_user(context, request): |
||||||
|
if "Cancel" in request.POST: |
||||||
|
return HTTPFound(request.resource_path(request.root)) |
||||||
|
|
||||||
|
form = RegistrationSchema.as_form(request) |
||||||
|
data = request.POST.items() |
||||||
|
try: |
||||||
|
appstruct = form.validate(data) |
||||||
|
except deform.ValidationFailure: |
||||||
|
return {"form": form} |
||||||
|
|
||||||
|
account = models.User( |
||||||
|
id=None, |
||||||
|
password=None, |
||||||
|
username=appstruct["user_name"], |
||||||
|
first_name=appstruct["first_name"], |
||||||
|
last_name=appstruct["last_name"], |
||||||
|
email=appstruct["email"], |
||||||
|
role=models.UserRole.NEW, |
||||||
|
) |
||||||
|
warnings = services.set_new_password(account, appstruct["password"]) |
||||||
|
request.repo.add_user(account) |
||||||
|
|
||||||
|
for message in warnings: |
||||||
|
request.flash("warning", message.message, message.description) |
||||||
|
|
||||||
|
return HTTPFound(request.resource_path(request.root, "registered")) |
||||||
|
|
||||||
|
|
||||||
|
@view_config( |
||||||
|
context="ordr3:resources.Root", |
||||||
|
name="registered", |
||||||
|
permission="view", |
||||||
|
renderer="ordr3:templates/account/registration_complete.jinja2", |
||||||
|
) |
||||||
|
def registration_complete(context, request): |
||||||
|
return {} |
||||||
|
|
||||||
|
|
||||||
|
@view_config( |
||||||
|
context="ordr3:resources.Root", |
||||||
|
name="breached", |
||||||
|
permission="view", |
||||||
|
renderer="ordr3:templates/account/breached_password.jinja2", |
||||||
|
) |
||||||
|
def breached_password(context, request): |
||||||
|
return {} |
Loading…
Reference in new issue