Adding Signup Table

This commit is contained in:
stephb9959
2022-02-22 14:47:43 -08:00
parent b63a886d86
commit fb01f895d4
15 changed files with 246 additions and 26 deletions

View File

@@ -128,7 +128,7 @@ add_executable(owprov
src/WebSocketClientServer.cpp src/WebSocketClientServer.h
src/storage/storage_maps.cpp src/storage/storage_maps.h
src/RESTAPI/RESTAPI_map_handler.cpp src/RESTAPI/RESTAPI_map_handler.h
src/RESTAPI/RESTAPI_map_list_handler.cpp src/RESTAPI/RESTAPI_map_list_handler.h src/storage/storage_signup.cpp src/storage/storage_signup.h)
src/RESTAPI/RESTAPI_map_list_handler.cpp src/RESTAPI/RESTAPI_map_list_handler.h src/storage/storage_signup.cpp src/storage/storage_signup.h src/Signup.cpp src/Signup.h)
target_link_libraries(owprov PUBLIC
${Poco_LIBRARIES} ${MySQL_LIBRARIES}

2
build
View File

@@ -1 +1 @@
22
24

View File

@@ -568,7 +568,7 @@ components:
type: string
devClass:
type: string
enum:4
enum:
- any
- venue
- entity
@@ -734,6 +734,31 @@ components:
reason:
type: string
SignupEntry:
type: object
properties:
allOf:
$ref: '#/components/schemas/ObjectInfo'
email:
type: string
format: email
userId:
type: string
format: uuid
serialNumber:
type: string
created:
type: integer
format: int64
completed:
type: integer
format: int64
error:
type: integer
format: int64
status:
type: string
#########################################################################################
##
## These are endpoints that all services in the OPenWiFI stack must provide
@@ -2571,16 +2596,7 @@ paths:
required: true
responses:
200:
description: Success signup post
content:
application/json:
schema:
type:
object
properties:
signupUUID:
type: string
format: uuid
$ref: '#/components/schemas/SignupEntry'
400:
$ref: '#/components/responses/BadRequest'
403:
@@ -2625,11 +2641,13 @@ paths:
errorCode:
type: integer
format: int32
status:
type: string
required: false
responses:
200:
$ref: '#/components/responses/Success'
$ref: '#/components/schemas/SignupEntry'
400:
$ref: '#/components/responses/BadRequest'
403:

View File

@@ -70,6 +70,9 @@ openwifi.kafka.ssl.certificate.location =
openwifi.kafka.ssl.key.location =
openwifi.kafka.ssl.key.password =
signup.graceperiod = 3600
signup.lingerperiod = 84400
#
# This section select which form of persistence you need
# Only one selected at a time. If you select multiple, this service will die if a horrible

View File

@@ -18,6 +18,7 @@
#include "JobController.h"
#include "WebSocketClientServer.h"
#include "FindCountry.h"
#include "Signup.h"
namespace OpenWifi {
class Daemon *Daemon::instance_ = nullptr;
@@ -36,7 +37,8 @@ namespace OpenWifi {
AutoDiscovery(),
JobController(),
WebSocketClientServer(),
FindCountryFromIP()
FindCountryFromIP(),
Signup()
});
}
return instance_;

View File

@@ -4,14 +4,16 @@
#include "RESTAPI_signup_handler.h"
#include "StorageService.h"
#include "RESTObjects/RESTAPI_SecurityObjects.h"
#include "Signup.h"
namespace OpenWifi {
void RESTAPI_signup_handler::DoPost() {
auto UserName = GetParameter("email","");
Poco::toLowerInPlace(UserName);
auto SerialNumber = GetParameter("serialNumber","");
Poco::toLowerInPlace(SerialNumber);
if(UserName.empty() || SerialNumber.empty()) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
@@ -25,15 +27,134 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::InvalidSerialNumber);
}
// let's see if the user already exists. If so, we will try and see if
// it's just
// Do we already exist? Can only signup once...
return OK();
// if a signup already exists for this user, we should just return its value
// or its completion
SignupDB::RecordVec SEs;
if(StorageService()->SignupDB().GetRecords(0,100, SEs, "email='" + UserName + "'")) {
for(const auto &i:SEs) {
if((i.created + Signup()->GracePeriod()) > OpenWifi::Now() && i.serialNumber==SerialNumber) {
Poco::JSON::Object Answer;
i.to_json(Answer);
return ReturnObject(Answer);
} else if((i.created + Signup()->GracePeriod()) < OpenWifi::Now() && i.completed==0) {
StorageService()->SignupDB().DeleteRecord("id", i.info.id);
}
}
}
// So we do not have an outstanding signup...
// Can we actually claim this serial number??? if not, we need to return an error
ProvObjects::InventoryTag IT;
if(StorageService()->InventoryDB().GetRecord("serialNumber",SerialNumber,IT)) {
if(!IT.subscriber.empty()) {
return BadRequest(RESTAPI::Errors::SerialNumberAlreadyProvisioned);
}
if(!(IT.devClass.empty() || IT.devClass=="subscriber" || IT.devClass=="any")) {
return BadRequest(RESTAPI::Errors::SerialNumberNotTheProperClass);
}
}
// OK, we can claim this device, can we create a userid?
// Let's create one
// If sec.signup("email",uuid);
auto SignupUUID = MicroService::instance().CreateUUID();
Poco::JSON::Object Body;
OpenAPIRequestPost CreateUser( uSERVICE_SECURITY, "/api/v1/signup", {
{ "email", UserName },
{ "signupUUID" , SignupUUID }
}, Body, 30000);
Poco::JSON::Object::Ptr Answer;
if(CreateUser.Do(Answer)) {
SecurityObjects::UserInfo UI;
UI.from_json(Answer);
// so create the Signup entry and modify the inventory
ProvObjects::SignupEntry SE;
SE.info.id = SignupUUID;
SE.info.created = SE.info.modified = SE.created = OpenWifi::Now();
SE.completed = 0 ;
SE.serialNumber = SerialNumber;
SE.error = 0 ;
SE.userId = UI.id;
SE.email = UserName;
SE.status = "waiting-for-email-verification";
std::cout << "Creating signup entry: " << SE.email << std::endl;
StorageService()->SignupDB().CreateRecord(SE);
// We do not have a device, so let's create one.
if(IT.serialNumber.empty()) {
IT.serialNumber = SerialNumber;
IT.info.id = MicroService::instance().CreateUUID();
IT.info.created = IT.info.modified = OpenWifi::Now();
Poco::JSON::Object StateDoc;
StateDoc.set("method", "signup");
StateDoc.set("claimer", UserName);
StateDoc.set("claimId", UI.id);
StateDoc.set("errorCode",0);
StateDoc.set("date", OpenWifi::Now());
StateDoc.set("status", "waiting for email-verification");
std::ostringstream os;
StateDoc.stringify(os);
IT.state = os.str();
std::cout << "Creating inventory entry: " << SE.serialNumber << std::endl;
StorageService()->InventoryDB().CreateRecord(IT);
} else {
Poco::JSON::Object StateDoc;
StateDoc.set("method", "signup");
StateDoc.set("claimer", UserName);
StateDoc.set("claimId", UI.id);
StateDoc.set("errorCode",0);
StateDoc.set("date", OpenWifi::Now());
StateDoc.set("status", "waiting for email-verification");
std::ostringstream os;
StateDoc.stringify(os);
IT.state = os.str();
IT.info.modified = OpenWifi::Now();
std::cout << "Updating inventory entry: " << SE.serialNumber << std::endl;
StorageService()->InventoryDB().UpdateRecord("id",IT.info.id,IT);
}
Poco::JSON::Object SEAnswer;
SE.to_json(SEAnswer);
return ReturnObject(SEAnswer);
}
return BadRequest(RESTAPI::Errors::UserAlreadyExists);
}
// this will be called by the SEC backend once the password has been verified.
void RESTAPI_signup_handler::DoPut() {
// TODO
auto SignupUUID = GetParameter("signupUUID","");
auto Operation = GetParameter("operation","");
if(SignupUUID.empty() || Operation.empty()) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
ProvObjects::SignupEntry SE;
if(!StorageService()->SignupDB().GetRecord("id",SignupUUID,SE)) {
return NotFound();
}
if(Operation == "emailVerified") {
std::cout << "Verified email for : " << SE.email << std::endl;
SE.info.modified = OpenWifi::Now();
SE.status = "emailVerified";
StorageService()->SignupDB().UpdateRecord("id", SE.info.id, SE);
Poco::JSON::Object Answer;
SE.to_json(Answer);
return ReturnObject(Answer);
}
}
}

View File

@@ -610,6 +610,8 @@ namespace OpenWifi::ProvObjects {
RESTAPI_utils::field_to_json( Obj,"serialNumber", serialNumber);
RESTAPI_utils::field_to_json( Obj,"created", created);
RESTAPI_utils::field_to_json( Obj,"completed", completed);
RESTAPI_utils::field_to_json( Obj,"status", status);
RESTAPI_utils::field_to_json( Obj,"error", error);
}
bool SignupEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
@@ -620,6 +622,8 @@ namespace OpenWifi::ProvObjects {
RESTAPI_utils::field_from_json( Obj,"serialNumber", serialNumber);
RESTAPI_utils::field_from_json( Obj,"created", created);
RESTAPI_utils::field_from_json( Obj,"completed", completed);
RESTAPI_utils::field_from_json( Obj,"status", status);
RESTAPI_utils::field_from_json( Obj,"error", error);
return true;
} catch(...) {

View File

@@ -393,6 +393,8 @@ namespace OpenWifi::ProvObjects {
std::string serialNumber;
uint64_t created = 0 ;
uint64_t completed = 0 ;
std::string status;
uint64_t error=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);

20
src/Signup.cpp Normal file
View File

@@ -0,0 +1,20 @@
//
// Created by stephane bourque on 2022-02-22.
//
#include "Signup.h"
namespace OpenWifi {
int Signup::Start() {
GracePeriod_ = MicroService::instance().ConfigGetInt("signup.graceperiod", 60*60);
LingerPeriod_ = MicroService::instance().ConfigGetInt("signup.lingerperiod", 24*60*60);
return 0;
}
void Signup::Stop() {
}
}

37
src/Signup.h Normal file
View File

@@ -0,0 +1,37 @@
//
// Created by stephane bourque on 2022-02-22.
//
#pragma once
#include "framework/MicroService.h"
namespace OpenWifi {
class Signup : public SubSystemServer {
public:
static auto instance() {
static auto instance_ = new Signup;
return instance_;
}
int Start() override;
void Stop() override;
inline uint64_t GracePeriod() const { return GracePeriod_; };
inline uint64_t LingerPeriod() const { return LingerPeriod_; }
private:
uint64_t GracePeriod_ = 60 * 60;
uint64_t LingerPeriod_ = 24 * 60 * 60;
Signup() noexcept:
SubSystemServer("SignupServer", "SIGNUP", "signup")
{
}
};
inline auto Signup() { return Signup::instance(); }
}

View File

@@ -86,6 +86,8 @@ using namespace std::chrono_literals;
namespace OpenWifi {
inline uint64_t Now() { return std::time(nullptr); };
enum UNAUTHORIZED_REASON {
SUCCESS=0,
PASSWORD_CHANGE_REQUIRED,

View File

@@ -467,8 +467,9 @@ namespace ORM {
}
typedef std::vector<RecordTuple> RecordList;
typedef std::vector<RecordType> RecordVec;
bool GetRecords( uint64_t Offset, uint64_t HowMany, std::vector<RecordType> & Records, const std::string & Where = "", const std::string & OrderBy = "") {
bool GetRecords( uint64_t Offset, uint64_t HowMany, RecordVec & Records, const std::string & Where = "", const std::string & OrderBy = "") {
try {
Poco::Data::Session Session = Pool_.get();
Poco::Data::Statement Select(Session);

View File

@@ -67,6 +67,9 @@ namespace OpenWifi::RESTAPI::Errors {
static const std::string SMSCouldNotBeSentRetry{"SMS could not be sent to validate device, try later or change the phone number."};
static const std::string SMSCouldNotValidate{"Code and number could not be validated"};
static const std::string InvalidDeviceClass{"Invalid device class. Must be: any, venue, entity, or subscriber"};
static const std::string SerialNumberAlreadyProvisioned{"This device has already been provisioned to a subscriber."};
static const std::string SerialNumberNotTheProperClass{"Device is not available to subscribers. It ahs been assigned to another class of devices."};
static const std::string UserAlreadyExists{"Username already exists."};
}
namespace OpenWifi::RESTAPI::Protocol {
@@ -214,6 +217,9 @@ namespace OpenWifi::uCentralProtocol {
static const char * FIRMWARE = "firmware";
static const char * CONNECT = "connect";
static const char * STATE = "state";
static const char * STATUS = "status";
static const char * ERROR = "error";
static const char * TEXT = "text";
static const char * HEALTHCHECK = "healthcheck";
static const char * LOG = "log";
static const char * CRASHLOG = "crashlog";

View File

@@ -23,7 +23,8 @@ namespace OpenWifi {
ORM::Field{"userId",ORM::FieldType::FT_TEXT},
ORM::Field{"serialNumber",ORM::FieldType::FT_TEXT},
ORM::Field{"created",ORM::FieldType::FT_BIGINT},
ORM::Field{"completed",ORM::FieldType::FT_BIGINT}
ORM::Field{"completed",ORM::FieldType::FT_BIGINT},
ORM::Field{"status",ORM::FieldType::FT_TEXT}
};
const static ORM::IndexVec SignupDB_Indexes{
@@ -51,6 +52,7 @@ template<> void ORM::DB< OpenWifi::SignupDBRecordType, OpenWifi::ProvObjects:
Out.serialNumber = In.get<8>();
Out.created = In.get<9>();
Out.completed = In.get<10>();
Out.status = In.get<11>();
}
template<> void ORM::DB< OpenWifi::SignupDBRecordType, OpenWifi::ProvObjects::SignupEntry>::Convert(const OpenWifi::ProvObjects::SignupEntry &In, OpenWifi::SignupDBRecordType &Out) {
@@ -65,4 +67,5 @@ template<> void ORM::DB< OpenWifi::SignupDBRecordType, OpenWifi::ProvObjects:
Out.set<8>(In.serialNumber);
Out.set<9>(In.created);
Out.set<10>(In.created);
Out.set<11>(In.status);
}

View File

@@ -19,7 +19,8 @@ namespace OpenWifi {
std::string,
std::string,
uint64_t,
uint64_t
uint64_t,
std::string
> SignupDBRecordType;
class SignupDB : public ORM::DB<SignupDBRecordType, ProvObjects::SignupEntry> {