mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralsec.git
synced 2025-10-29 18:02:29 +00:00
Adding Sub Signup
This commit is contained in:
@@ -122,7 +122,7 @@ add_executable( owsec
|
||||
src/storage/orm_actionLinks.cpp src/storage/orm_actionLinks.h
|
||||
src/storage/orm_avatar.cpp src/storage/orm_avatar.h
|
||||
src/SpecialUserHelpers.h
|
||||
src/RESTAPI/RESTAPI_db_helpers.h src/storage/orm_logins.cpp src/storage/orm_logins.h src/RESTAPI/RESTAPI_totp_handler.cpp src/RESTAPI/RESTAPI_totp_handler.h src/TotpCache.h src/RESTAPI/RESTAPI_subtotp_handler.cpp src/RESTAPI/RESTAPI_subtotp_handler.h)
|
||||
src/RESTAPI/RESTAPI_db_helpers.h src/storage/orm_logins.cpp src/storage/orm_logins.h src/RESTAPI/RESTAPI_totp_handler.cpp src/RESTAPI/RESTAPI_totp_handler.h src/TotpCache.h src/RESTAPI/RESTAPI_subtotp_handler.cpp src/RESTAPI/RESTAPI_subtotp_handler.h src/RESTAPI/RESTAPI_signup_handler.cpp src/RESTAPI/RESTAPI_signup_handler.h)
|
||||
|
||||
if(NOT SMALL_BUILD)
|
||||
target_link_libraries(owsec PUBLIC
|
||||
|
||||
@@ -1484,6 +1484,32 @@ paths:
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
|
||||
/signup:
|
||||
post:
|
||||
tags:
|
||||
- Subscriber Registration
|
||||
summary: This call allows a new subscriber to register themselves and their devices.
|
||||
operationId: postSignup
|
||||
parameters:
|
||||
- in: query
|
||||
name: email
|
||||
schema:
|
||||
type: string
|
||||
format: email
|
||||
required: true
|
||||
- in: query
|
||||
name: serialNumber
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/responses/Success'
|
||||
400:
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
404:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
|
||||
#########################################################################################
|
||||
##
|
||||
## These are endpoints that all services in the uCentral stack must provide
|
||||
|
||||
@@ -86,6 +86,14 @@ namespace OpenWifi {
|
||||
}
|
||||
break;
|
||||
|
||||
case OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP: {
|
||||
if(AuthService::SendEmailToSubUser(i.id, UInfo.email, AuthService::SIGNUP_VERIFICATION)) {
|
||||
Logger().information(Poco::format("Send new subscriber email verification link to %s",UInfo.email));
|
||||
}
|
||||
StorageService()->ActionLinksDB().SentAction(i.id);
|
||||
}
|
||||
break;
|
||||
|
||||
default: {
|
||||
StorageService()->ActionLinksDB().SentAction(i.id);
|
||||
}
|
||||
|
||||
@@ -16,17 +16,18 @@ namespace OpenWifi {
|
||||
FORGOT_PASSWORD,
|
||||
VERIFY_EMAIL,
|
||||
SUB_FORGOT_PASSWORD,
|
||||
SUB_VERIFY_EMAIL
|
||||
SUB_VERIFY_EMAIL,
|
||||
SUB_SIGNUP
|
||||
};
|
||||
*/
|
||||
static ActionLinkManager * instance() {
|
||||
static auto * instance_ = new ActionLinkManager;
|
||||
static auto instance_ = new ActionLinkManager;
|
||||
return instance_;
|
||||
}
|
||||
|
||||
int Start() final;
|
||||
void Stop() final;
|
||||
void run();
|
||||
void run() final;
|
||||
|
||||
private:
|
||||
Poco::Thread Thr_;
|
||||
|
||||
@@ -546,6 +546,17 @@ namespace OpenWifi {
|
||||
}
|
||||
break;
|
||||
|
||||
case SIGNUP_VERIFICATION: {
|
||||
MessageAttributes Attrs;
|
||||
Attrs[RECIPIENT_EMAIL] = UInfo.email;
|
||||
Attrs[LOGO] = GetLogoAssetURI();
|
||||
Attrs[SUBJECT] = "EMail Address Verification";
|
||||
Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=signup_verification&id=" + LinkId ;
|
||||
SMTPMailerService()->SendMessage(UInfo.email, "signup_verification.txt", Attrs);
|
||||
UInfo.waitingForEmailCheck = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,8 @@ namespace OpenWifi{
|
||||
|
||||
enum EMAIL_REASON {
|
||||
FORGOT_PASSWORD,
|
||||
EMAIL_VERIFICATION
|
||||
EMAIL_VERIFICATION,
|
||||
SIGNUP_VERIFICATION
|
||||
};
|
||||
|
||||
static ACCESS_TYPE IntToAccessType(int C);
|
||||
|
||||
@@ -25,6 +25,8 @@ namespace OpenWifi {
|
||||
return RequestResetPassword(Link);
|
||||
else if(Action=="email_verification")
|
||||
return DoEmailVerification(Link);
|
||||
else if(Action=="signup_verification")
|
||||
return DoNewSubVerification(Link);
|
||||
else
|
||||
return DoReturnA404();
|
||||
}
|
||||
@@ -34,6 +36,8 @@ namespace OpenWifi {
|
||||
|
||||
if(Action=="password_reset")
|
||||
return CompleteResetPassword();
|
||||
else if(Action=="signup_completion")
|
||||
return CompleteSubVerification();
|
||||
else
|
||||
return DoReturnA404();
|
||||
}
|
||||
@@ -46,6 +50,14 @@ namespace OpenWifi {
|
||||
SendHTMLFileBack(FormFile,FormVars);
|
||||
}
|
||||
|
||||
void RESTAPI_action_links::DoNewSubVerification(SecurityObjects::ActionLink &Link) {
|
||||
Logger_.information(Poco::format("REQUEST-SUB-SIGNUP(%s): For ID=%s", Request->clientAddress().toString(), Link.userId));
|
||||
Poco::File FormFile{ Daemon()->AssetDir() + "/signup_verification.html"};
|
||||
Types::StringPairVec FormVars{ {"UUID", Link.id},
|
||||
{"PASSWORD_VALIDATION", AuthService()->PasswordValidationExpression()}};
|
||||
SendHTMLFileBack(FormFile,FormVars);
|
||||
}
|
||||
|
||||
void RESTAPI_action_links::CompleteResetPassword() {
|
||||
// form has been posted...
|
||||
RESTAPI_PartHandler PartHandler;
|
||||
@@ -53,7 +65,7 @@ namespace OpenWifi {
|
||||
if (!Form.empty()) {
|
||||
|
||||
auto Password1 = Form.get("password1","bla");
|
||||
auto Password2 = Form.get("password1","blu");
|
||||
auto Password2 = Form.get("password2","blu");
|
||||
auto Id = Form.get("id","");
|
||||
auto Now = std::time(nullptr);
|
||||
|
||||
@@ -118,6 +130,77 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
void RESTAPI_action_links::CompleteSubVerification() {
|
||||
RESTAPI_PartHandler PartHandler;
|
||||
Poco::Net::HTMLForm Form(*Request, Request->stream(), PartHandler);
|
||||
|
||||
if (!Form.empty()) {
|
||||
auto Password1 = Form.get("password1","bla");
|
||||
auto Password2 = Form.get("password2","blu");
|
||||
auto Id = Form.get("id","");
|
||||
auto Now = std::time(nullptr);
|
||||
|
||||
SecurityObjects::ActionLink Link;
|
||||
if(!StorageService()->ActionLinksDB().GetActionLink(Id,Link)) {
|
||||
return DoReturnA404();
|
||||
}
|
||||
|
||||
if(Now > Link.expires) {
|
||||
StorageService()->ActionLinksDB().CancelAction(Id);
|
||||
return DoReturnA404();
|
||||
}
|
||||
|
||||
if(Password1!=Password2 || !AuthService()->ValidateSubPassword(Password1)) {
|
||||
Poco::File FormFile{ Daemon()->AssetDir() + "/password_reset_error.html"};
|
||||
Types::StringPairVec FormVars{ {"UUID", Id},
|
||||
{"ERROR_TEXT", "For some reason, the passwords entered do not match or they do not comply with"
|
||||
" accepted password creation restrictions. Please consult our on-line help"
|
||||
" to look at the our password policy. If you would like to contact us, please mention"
|
||||
" id(" + Id + ")"}};
|
||||
return SendHTMLFileBack(FormFile,FormVars);
|
||||
}
|
||||
|
||||
SecurityObjects::UserInfo UInfo;
|
||||
bool Found = StorageService()->SubDB().GetUserById(Link.userId,UInfo);
|
||||
if(!Found) {
|
||||
Poco::File FormFile{ Daemon()->AssetDir() + "/signup_verification_error.html"};
|
||||
Types::StringPairVec FormVars{ {"UUID", Id},
|
||||
{"ERROR_TEXT", "This request does not contain a valid user ID. Please contact your system administrator."}};
|
||||
return SendHTMLFileBack(FormFile,FormVars);
|
||||
}
|
||||
|
||||
if(UInfo.blackListed || UInfo.suspended) {
|
||||
Poco::File FormFile{ Daemon()->AssetDir() + "/signup_verification_error.html"};
|
||||
Types::StringPairVec FormVars{ {"UUID", Id},
|
||||
{"ERROR_TEXT", "Please contact our system administrators. We have identified an error in your account that must be resolved first."}};
|
||||
return SendHTMLFileBack(FormFile,FormVars);
|
||||
}
|
||||
|
||||
bool GoodPassword = AuthService()->SetSubPassword(Password1,UInfo);
|
||||
if(!GoodPassword) {
|
||||
Poco::File FormFile{ Daemon()->AssetDir() + "/signup_verification_error.html"};
|
||||
Types::StringPairVec FormVars{ {"UUID", Id},
|
||||
{"ERROR_TEXT", "You cannot reuse one of your recent passwords."}};
|
||||
return SendHTMLFileBack(FormFile,FormVars);
|
||||
}
|
||||
|
||||
UInfo.modified = std::time(nullptr);
|
||||
UInfo.changePassword = false;
|
||||
UInfo.lastEmailCheck = std::time(nullptr);
|
||||
UInfo.waitingForEmailCheck = false;
|
||||
|
||||
StorageService()->SubDB().UpdateUserInfo(UInfo.email,Link.userId,UInfo);
|
||||
|
||||
Poco::File FormFile{ Daemon()->AssetDir() + "/signup_verification_success.html"};
|
||||
Types::StringPairVec FormVars{ {"UUID", Id},
|
||||
{"USERNAME", UInfo.email} };
|
||||
StorageService()->ActionLinksDB().CompleteAction(Id);
|
||||
SendHTMLFileBack(FormFile,FormVars);
|
||||
} else {
|
||||
DoReturnA404();
|
||||
}
|
||||
}
|
||||
|
||||
void RESTAPI_action_links::DoEmailVerification(SecurityObjects::ActionLink &Link) {
|
||||
auto Now = std::time(nullptr);
|
||||
|
||||
|
||||
@@ -23,8 +23,10 @@ namespace OpenWifi {
|
||||
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/actionLink"}; };
|
||||
void RequestResetPassword(SecurityObjects::ActionLink &Link);
|
||||
void CompleteResetPassword();
|
||||
void CompleteSubVerification();
|
||||
void DoEmailVerification(SecurityObjects::ActionLink &Link);
|
||||
void DoReturnA404();
|
||||
void DoNewSubVerification(SecurityObjects::ActionLink &Link);
|
||||
|
||||
void DoGet() final;
|
||||
void DoPost() final;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "RESTAPI/RESTAPI_submfa_handler.h"
|
||||
#include "RESTAPI/RESTAPI_totp_handler.h"
|
||||
#include "RESTAPI/RESTAPI_subtotp_handler.h"
|
||||
#include "RESTAPI/RESTAPI_signup_handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
@@ -48,7 +49,8 @@ namespace OpenWifi {
|
||||
RESTAPI_subusers_handler,
|
||||
RESTAPI_submfa_handler,
|
||||
RESTAPI_totp_handler,
|
||||
RESTAPI_subtotp_handler
|
||||
RESTAPI_subtotp_handler,
|
||||
RESTAPI_signup_handler
|
||||
>(Path, Bindings, L, S,TransactionId);
|
||||
}
|
||||
|
||||
@@ -67,7 +69,8 @@ namespace OpenWifi {
|
||||
RESTAPI_preferences,
|
||||
RESTAPI_subpreferences,
|
||||
RESTAPI_suboauth2_handler,
|
||||
RESTAPI_submfa_handler
|
||||
RESTAPI_submfa_handler,
|
||||
RESTAPI_signup_handler
|
||||
>(Path, Bindings, L, S, TransactionId);
|
||||
}
|
||||
}
|
||||
68
src/RESTAPI/RESTAPI_signup_handler.cpp
Normal file
68
src/RESTAPI/RESTAPI_signup_handler.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-02-20.
|
||||
//
|
||||
|
||||
#include "RESTAPI_signup_handler.h"
|
||||
#include "StorageService.h"
|
||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void RESTAPI_signup_handler::DoPost() {
|
||||
|
||||
auto UserName = GetParameter("email","");
|
||||
auto SerialNumber = GetParameter("serialNumber","");
|
||||
|
||||
if(UserName.empty() || SerialNumber.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||
}
|
||||
|
||||
if(!Utils::ValidEMailAddress(UserName)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidEmailAddress);
|
||||
}
|
||||
|
||||
if(!Utils::ValidSerialNumber(SerialNumber)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidSerialNumber);
|
||||
}
|
||||
|
||||
// Do we already exist? Can only signup once...
|
||||
SecurityObjects::UserInfo Existing;
|
||||
if(StorageService()->SubDB().GetUserByEmail(UserName,Existing)) {
|
||||
|
||||
if(Existing.signingUp.empty()) {
|
||||
return BadRequest(1, "Subscriber already signed up.");
|
||||
}
|
||||
|
||||
if(Existing.waitingForEmailCheck) {
|
||||
return BadRequest(2, "Waiting for email check completion.");
|
||||
}
|
||||
|
||||
return BadRequest(3, "Waiting for device:" + Existing.signingUp);
|
||||
}
|
||||
|
||||
SecurityObjects::UserInfo NewSub;
|
||||
NewSub.signingUp = SerialNumber;
|
||||
NewSub.waitingForEmailCheck = true;
|
||||
NewSub.modified = std::time(nullptr);
|
||||
NewSub.creationDate = std::time(nullptr);
|
||||
NewSub.id = MicroService::instance().CreateUUID();
|
||||
NewSub.email = UserName;
|
||||
NewSub.userRole = SecurityObjects::SUBSCRIBER;
|
||||
NewSub.changePassword = true;
|
||||
|
||||
StorageService()->SubDB().CreateRecord(NewSub);
|
||||
|
||||
Logger_.information(Poco::format("SIGNUP-PASSWORD(%s): Request for %s", Request->clientAddress().toString(), UserName));
|
||||
SecurityObjects::ActionLink NewLink;
|
||||
|
||||
NewLink.action = OpenWifi::SecurityObjects::LinkActions::SUB_SIGNUP;
|
||||
NewLink.id = MicroService::CreateUUID();
|
||||
NewLink.userId = NewSub.id;
|
||||
NewLink.created = std::time(nullptr);
|
||||
NewLink.expires = NewLink.created + (1*60*60); // 1 hour
|
||||
NewLink.userAction = false;
|
||||
StorageService()->ActionLinksDB().CreateAction(NewLink);
|
||||
|
||||
return OK();
|
||||
}
|
||||
}
|
||||
38
src/RESTAPI/RESTAPI_signup_handler.h
Normal file
38
src/RESTAPI/RESTAPI_signup_handler.h
Normal file
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// Created by stephane bourque on 2022-02-20.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_signup_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_signup_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer & Server, uint64_t TransactionId, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{
|
||||
Poco::Net::HTTPRequest::HTTP_POST,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Server,
|
||||
TransactionId,
|
||||
Internal, false, true ){}
|
||||
|
||||
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/action"}; };
|
||||
|
||||
/* inline bool RoleIsAuthorized(std::string & Reason) {
|
||||
if(UserInfo_.userinfo.userRole != SecurityObjects::USER_ROLE::SUBSCRIBER) {
|
||||
Reason = "User must be a subscriber";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
void DoGet() final {};
|
||||
void DoPost() final;
|
||||
void DoPut() final {};
|
||||
void DoDelete() final {};
|
||||
private:
|
||||
|
||||
};
|
||||
}
|
||||
@@ -257,6 +257,7 @@ namespace OpenWifi::SecurityObjects {
|
||||
field_to_json(Obj,"oauthType",oauthType);
|
||||
field_to_json(Obj,"oauthUserInfo",oauthUserInfo);
|
||||
field_to_json(Obj,"modified",modified);
|
||||
field_to_json(Obj,"signingUp",signingUp);
|
||||
};
|
||||
|
||||
bool UserInfo::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -292,6 +293,7 @@ namespace OpenWifi::SecurityObjects {
|
||||
field_from_json(Obj,"oauthType",oauthType);
|
||||
field_from_json(Obj,"oauthUserInfo",oauthUserInfo);
|
||||
field_from_json(Obj,"modified",modified);
|
||||
field_from_json(Obj,"signingUp",signingUp);
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
|
||||
@@ -138,6 +138,7 @@ namespace OpenWifi {
|
||||
std::string oauthType;
|
||||
std::string oauthUserInfo;
|
||||
uint64_t modified;
|
||||
std::string signingUp;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -233,7 +234,8 @@ namespace OpenWifi {
|
||||
FORGOT_PASSWORD=1,
|
||||
VERIFY_EMAIL,
|
||||
SUB_FORGOT_PASSWORD,
|
||||
SUB_VERIFY_EMAIL
|
||||
SUB_VERIFY_EMAIL,
|
||||
SUB_SIGNUP
|
||||
};
|
||||
|
||||
struct ActionLink {
|
||||
|
||||
@@ -73,7 +73,8 @@ namespace OpenWifi {
|
||||
ORM::Field{"lastPasswords", ORM::FieldType::FT_TEXT},
|
||||
ORM::Field{"oauthType", ORM::FieldType::FT_TEXT},
|
||||
ORM::Field{"oauthUserInfo", ORM::FieldType::FT_TEXT},
|
||||
ORM::Field{"modified", ORM::FieldType::FT_TEXT}
|
||||
ORM::Field{"modified", ORM::FieldType::FT_TEXT},
|
||||
ORM::Field{"signingUp", ORM::FieldType::FT_TEXT}
|
||||
};
|
||||
|
||||
static ORM::IndexVec MakeIndices(const std::string & shortname) {
|
||||
@@ -96,7 +97,8 @@ namespace OpenWifi {
|
||||
|
||||
bool BaseUserDB::Upgrade(uint32_t from, uint32_t &to) {
|
||||
std::vector<std::string> Statements{
|
||||
"alter table " + TableName_ + " add column modified BIGINT;"
|
||||
"alter table " + TableName_ + " add column modified BIGINT;",
|
||||
"alter table " + TableName_ + " add column signingUp TEXT default '';"
|
||||
};
|
||||
RunScript(Statements);
|
||||
to = CurrentVersion;
|
||||
@@ -314,6 +316,7 @@ template<> void ORM::DB<OpenWifi::UserInfoRecordTuple,
|
||||
U.oauthType = T.get<28>();
|
||||
U.oauthUserInfo = T.get<29>();
|
||||
U.modified = T.get<30>();
|
||||
U.signingUp = T.get<31>();
|
||||
}
|
||||
|
||||
template<> void ORM::DB< OpenWifi::UserInfoRecordTuple,
|
||||
@@ -350,4 +353,5 @@ template<> void ORM::DB< OpenWifi::UserInfoRecordTuple,
|
||||
T.set<28>(U.oauthType);
|
||||
T.set<29>(U.oauthUserInfo);
|
||||
T.set<30>(U.modified);
|
||||
T.set<31>(U.signingUp);
|
||||
}
|
||||
|
||||
@@ -40,7 +40,8 @@ namespace OpenWifi {
|
||||
std::string, // lastPasswords;
|
||||
std::string, // oauthType;
|
||||
std::string, // oauthUserInfo;
|
||||
uint64_t // modified
|
||||
uint64_t, // modified
|
||||
std::string // signingUp;
|
||||
> UserInfoRecordTuple;
|
||||
|
||||
typedef std::vector <UserInfoRecordTuple> UserInfoRecordTupleList;
|
||||
@@ -62,7 +63,7 @@ namespace OpenWifi {
|
||||
|
||||
class BaseUserDB : public ORM::DB<UserInfoRecordTuple, SecurityObjects::UserInfo> {
|
||||
public:
|
||||
const uint32_t CurrentVersion = 1;
|
||||
const uint32_t CurrentVersion = 2;
|
||||
BaseUserDB( const std::string &name, const std::string &shortname, OpenWifi::DBType T, Poco::Data::SessionPool & P, Poco::Logger &L, UserCache * Cache, bool users);
|
||||
|
||||
bool CreateUser(const std::string & Admin, SecurityObjects::UserInfo & NewUser, bool PasswordHashedAlready = false );
|
||||
|
||||
10
templates/signup_verification.html
Normal file
10
templates/signup_verification.html
Normal file
@@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Title</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
10
templates/signup_verification.txt
Normal file
10
templates/signup_verification.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
Dear ${RECIPIENT_EMAIL},
|
||||
|
||||
Before you can access the system, you must validate your e-mail address. Please click on the link below
|
||||
to complete this task.
|
||||
|
||||
${ACTION_LINK}
|
||||
|
||||
And follow the instructions.
|
||||
|
||||
Thank you!
|
||||
162
wwwassets/signup_verification.html
Normal file
162
wwwassets/signup_verification.html
Normal file
@@ -0,0 +1,162 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial,
|
||||
Helvetica, sans-serif;
|
||||
background-color: #ebedef;
|
||||
}
|
||||
|
||||
.body {
|
||||
background-color: #ebedef;
|
||||
}
|
||||
|
||||
input[type=text], input[type=password] {
|
||||
width: 90%;
|
||||
padding: 12px 20px;
|
||||
margin: 8px 0;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: #04AA6D;
|
||||
color: white;
|
||||
padding: 14px 20px;
|
||||
margin: 8px 0;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
width: 40%;
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.imgcontainer {
|
||||
width: 100%;
|
||||
margin-top: 5%;
|
||||
text-align: center;
|
||||
display: block;
|
||||
}
|
||||
|
||||
img.avatar {
|
||||
width: 40%;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.grid-container {
|
||||
display: grid;
|
||||
grid-template-columns: 15% 70% 15%;
|
||||
grid-column-gap: 5px;
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
text-align: center;
|
||||
padding: 30px;
|
||||
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
|
||||
display: block;
|
||||
width: 50%;
|
||||
border: 1em;
|
||||
background-color: white;
|
||||
width: 40%;
|
||||
height: auto;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: auto;
|
||||
margin-top: 50px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.passwordtext {
|
||||
float: left;
|
||||
margin-left: 5%;
|
||||
}
|
||||
|
||||
.password-input {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
.rulestext {
|
||||
width: 95%;
|
||||
margin: auto;
|
||||
display: inline-block;
|
||||
text-align: left;
|
||||
text-justify: none;
|
||||
margin: 5px 0 5px 0;
|
||||
grid-column-start: 2;
|
||||
grid-column-end: 2;
|
||||
}
|
||||
|
||||
ul {
|
||||
display: inline-block;
|
||||
text-align: left;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
span.password1 {
|
||||
float: right;
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
/* Change styles for span and cancel button on extra small screens */
|
||||
@media screen and (max-width: 300px) {
|
||||
span.password1 {
|
||||
display: block;
|
||||
float: none;
|
||||
}
|
||||
.cancelbtn {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="imgcontainer">
|
||||
<img src="/wwwassets/the_logo.png" alt="OpenWifi">
|
||||
</div>
|
||||
|
||||
<form action="/api/v1/actionLink?action=signup_completion" method="post" onsubmit="return validatePassword()">
|
||||
<input type="hidden" id="custId" name="id" value="${UUID}">
|
||||
<div class="grid-container">
|
||||
<h2>Reset Password</h2>
|
||||
<div class="passwordlabel">
|
||||
<label class="passwordtext" for="password1" ><b>New Password</b></label>
|
||||
<input className="password-input" id="password1" type="password" placeholder="New Password" name="password1" pattern="${PASSWORD_VALIDATION}" required>
|
||||
</div>
|
||||
<div class="passwordlabel">
|
||||
<label class="passwordtext" for="password2"><b>Retype Password</b></label>
|
||||
<input className="password-input" id="password2" type="password" placeholder="Retype Password" name="password2" pattern="${PASSWORD_VALIDATION}" required>
|
||||
</div>
|
||||
<div class="passwordlabel">
|
||||
<button type="submit">Reset Password</button>
|
||||
</div>
|
||||
|
||||
<div class="rulestext">
|
||||
<ul>
|
||||
<li>Must be at least 8 characters long</li>
|
||||
<li>Must contain 1 uppercase letter</li>
|
||||
<li>Must contain 1 lowercase letter</li>
|
||||
<li>Must contain 1 digit</li>
|
||||
<li>Must contain 1 special character</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
function validatePassword() {
|
||||
if(document.getElementById("password1").value == document.getElementById("password2").value) {
|
||||
return true;
|
||||
} else {
|
||||
alert("The 2 passwords did not match. The passwords must match to reset your new password.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
116
wwwassets/signup_verification_error.html
Normal file
116
wwwassets/signup_verification_error.html
Normal file
@@ -0,0 +1,116 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
body {font-family: Arial, Helvetica, sans-serif;}
|
||||
form {border: 3px solid #f1f1f1;}
|
||||
|
||||
input[type=text], input[type=password] {
|
||||
width: 100%;
|
||||
padding: 12px 20px;
|
||||
margin: 8px 0;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: #04AA6D;
|
||||
color: white;
|
||||
padding: 14px 20px;
|
||||
margin: 8px 0;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.imgcontainer {
|
||||
width: 100%;
|
||||
margin-top: 5%;
|
||||
text-align: center;
|
||||
display: block;
|
||||
}
|
||||
|
||||
img.avatar {
|
||||
width: 40%;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.info-card {
|
||||
padding: 30px;
|
||||
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
|
||||
display: block;
|
||||
width: 50%;
|
||||
border: 1em;
|
||||
background-color: white;
|
||||
width: 40%;
|
||||
height: auto;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: auto;
|
||||
margin-top: 50px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.info-list {
|
||||
width: 80%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.info-title {
|
||||
padding-bottom: 20px;
|
||||
width: 80%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.body {
|
||||
background-color: #ebedef;
|
||||
}
|
||||
|
||||
span.password1 {
|
||||
float: right;
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
/* Change styles for span and cancel button on extra small screens */
|
||||
@media screen and (max-width: 300px) {
|
||||
span.password1 {
|
||||
display: block;
|
||||
float: none;
|
||||
}
|
||||
.cancelbtn {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="body">
|
||||
|
||||
<div class="imgcontainer">
|
||||
<img src="/wwwassets/the_logo.png" alt="OpenWifi">
|
||||
</div>
|
||||
|
||||
|
||||
<div class="info-card">
|
||||
<h1 class="info-title">Reset Password Failed</h1>
|
||||
<div>
|
||||
<h3>ID</h3>
|
||||
<b>${UUID}</b>
|
||||
</div>
|
||||
<div>
|
||||
<h3>Error</h3>
|
||||
<b>${ERROR_TEXT}</b>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
76
wwwassets/signup_verification_success.html
Normal file
76
wwwassets/signup_verification_success.html
Normal file
@@ -0,0 +1,76 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
body {font-family: Arial, Helvetica, sans-serif;}
|
||||
form {border: 3px solid #f1f1f1;}
|
||||
|
||||
input[type=text], input[type=password] {
|
||||
width: 100%;
|
||||
padding: 12px 20px;
|
||||
margin: 8px 0;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: #04AA6D;
|
||||
color: white;
|
||||
padding: 14px 20px;
|
||||
margin: 8px 0;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.imgcontainer {
|
||||
text-align: center;
|
||||
margin: 24px 0 12px 0;
|
||||
}
|
||||
|
||||
img.avatar {
|
||||
width: 40%;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
span.password1 {
|
||||
float: right;
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
/* Change styles for span and cancel button on extra small screens */
|
||||
@media screen and (max-width: 300px) {
|
||||
span.password1 {
|
||||
display: block;
|
||||
float: none;
|
||||
}
|
||||
.cancelbtn {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="imgcontainer">
|
||||
<img src="/wwwassets/the_logo.png" alt="Avatar" class="avatar">
|
||||
</div>
|
||||
|
||||
<h1>Signup was successfully done</h1>
|
||||
<div>
|
||||
<h3>Thank you ${USERNAME} for signing up for service.</h3>
|
||||
</div>
|
||||
<div>
|
||||
You can access your account using the mobile app.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user