Improving Subscriber Signup

This commit is contained in:
stephb9959
2022-02-26 09:48:15 -08:00
parent 6a9d0cee55
commit ac905c92b5
13 changed files with 151 additions and 51 deletions

2
build
View File

@@ -1 +1 @@
40
41

View File

@@ -507,6 +507,9 @@ components:
items:
type: string
format: uuid
subscriberOnly:
type: boolean
default: false
rrm:
type: string
enum:
@@ -762,6 +765,9 @@ components:
format: int64
status:
type: string
statusCode:
type: integer
format: int64
Variable:
type: object
@@ -2794,10 +2800,8 @@ paths:
type: string
enum:
- cancel
- success
- inprogress
- failed
- poll
- emailVerified
- deviceVerified
required: true
requestBody:
content:

View File

@@ -115,8 +115,16 @@ namespace OpenWifi{
if(!Existing.contact.empty())
StorageService()->ContactDB().DeleteInUse("id",Existing.contact,DB_.Prefix(),Existing.info.id);
if(!Existing.deviceConfiguration.empty())
StorageService()->ConfigurationDB().DeleteInUse("id", Existing.deviceConfiguration, DB_.Prefix(), Existing.info.id);
if(!Existing.deviceConfiguration.empty()) {
ProvObjects::DeviceConfiguration DC;
if(StorageService()->ConfigurationDB().GetRecord("id", Existing.deviceConfiguration, DC)) {
if(DC.subscriberOnly)
StorageService()->ConfigurationDB().DeleteRecord("id", Existing.deviceConfiguration);
else
StorageService()->ConfigurationDB().DeleteInUse("id", Existing.deviceConfiguration, DB_.Prefix(),
Existing.info.id);
}
}
if(DB_.DeleteRecord("id", Existing.info.id)) {
DB_.DeleteRecord(RESTAPI::Protocol::ID, Existing.info.id);

View File

@@ -9,52 +9,42 @@
namespace OpenWifi {
void RESTAPI_signup_handler::DoPost() {
std::cout << __LINE__ << std::endl;
auto UserName = GetParameter("email","");
Poco::toLowerInPlace(UserName);
auto SerialNumber = GetParameter("serialNumber","");
Poco::toLowerInPlace(SerialNumber);
std::cout << __LINE__ << std::endl;
if(UserName.empty() || SerialNumber.empty()) {
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
}
std::cout << __LINE__ << std::endl;
if(!Utils::ValidEMailAddress(UserName)) {
return BadRequest(RESTAPI::Errors::InvalidEmailAddress);
}
std::cout << __LINE__ << std::endl;
if(!Utils::ValidSerialNumber(SerialNumber)) {
return BadRequest(RESTAPI::Errors::InvalidSerialNumber);
}
std::cout << __LINE__ << std::endl;
// if a signup already exists for this user, we should just return its value
// or its completion
// if a signup already exists for this user, we should just return its value completion
SignupDB::RecordVec SEs;
std::cout << __LINE__ << std::endl;
if(StorageService()->SignupDB().GetRecords(0,100, SEs, "email='" + UserName + "'")) {
if(StorageService()->SignupDB().GetRecords(0,100, SEs, " email='" + UserName + "' and serialNumber='"+SerialNumber+"' ")) {
for(const auto &i:SEs) {
if((i.submitted + Signup()->GracePeriod()) > OpenWifi::Now() && i.serialNumber==SerialNumber) {
Poco::JSON::Object Answer;
if (i.statusCode == ProvObjects::SignupStatusCodes::SignupWaitingForEmail ||
i.statusCode == ProvObjects::SignupStatusCodes::SignupWaitingForDevice ||
i.statusCode == ProvObjects::SignupStatusCodes::SignupSuccess ) {
Logger().information(Poco::format("SIGNUP: Returning existing signup record for '%s'",i.email));
Poco::JSON::Object Answer;
i.to_json(Answer);
return ReturnObject(Answer);
} else if((i.submitted + Signup()->GracePeriod()) < OpenWifi::Now() && i.completed==0) {
StorageService()->SignupDB().DeleteRecord("id", i.info.id);
}
}
}
std::cout << __LINE__ << std::endl;
// 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;
std::cout << __LINE__ << std::endl;
if(StorageService()->InventoryDB().GetRecord("serialNumber",SerialNumber,IT)) {
if(!IT.subscriber.empty()) {
return BadRequest(RESTAPI::Errors::SerialNumberAlreadyProvisioned);
}
@@ -63,13 +53,12 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::SerialNumberNotTheProperClass);
}
}
std::cout << __LINE__ << std::endl;
// 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();
std::cout << __LINE__ << std::endl;
Logger().information(Poco::format("SIGNUP: Creating signup entry for '%s', uuid=%s",UserName, SignupUUID));
Poco::JSON::Object Body;
OpenAPIRequestPost CreateUser( uSERVICE_SECURITY, "/api/v1/signup", {
@@ -77,7 +66,6 @@ namespace OpenWifi {
{ "signupUUID" , SignupUUID }
}, Body, 30000);
std::cout << __LINE__ << std::endl;
Poco::JSON::Object::Ptr Answer;
if(CreateUser.Do(Answer) == Poco::Net::HTTPServerResponse::HTTP_OK) {
SecurityObjects::UserInfo UI;
@@ -85,11 +73,10 @@ namespace OpenWifi {
UI.from_json(Answer);
std::ostringstream os;
Answer->stringify(os);
std::cout << "Create user: " << std::endl << os.str() << std::endl;
Logger().information(Poco::format("SIGNUP: email: '%s' signupID: '%s' userId: '%s'", UserName, SignupUUID, UI.id));
// so create the Signup entry and modify the inventory
ProvObjects::SignupEntry SE;
SE.info.id = SignupUUID;
SE.info.created = SE.info.modified = SE.submitted = OpenWifi::Now();
SE.completed = 0 ;
@@ -98,12 +85,10 @@ namespace OpenWifi {
SE.userId = UI.id;
SE.email = UserName;
SE.status = "waiting-for-email-verification";
std::cout << "Creating signup entry: " << SE.email << std::endl;
SE.statusCode = ProvObjects::SignupStatusCodes::SignupWaitingForEmail;
StorageService()->SignupDB().CreateRecord(SE);
Signup()->AddOutstandingSignup(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();
@@ -112,7 +97,8 @@ namespace OpenWifi {
Poco::JSON::Object StateDoc;
StateDoc.set("method", "signup");
StateDoc.set("claimer", UserName);
StateDoc.set("claimId", UI.id);
StateDoc.set("claimerId", UI.id);
StateDoc.set("signupUUID", SignupUUID);
StateDoc.set("errorCode",0);
StateDoc.set("date", OpenWifi::Now());
StateDoc.set("status", "waiting for email-verification");
@@ -125,7 +111,8 @@ namespace OpenWifi {
Poco::JSON::Object StateDoc;
StateDoc.set("method", "signup");
StateDoc.set("claimer", UserName);
StateDoc.set("claimId", UI.id);
StateDoc.set("claimerId", UI.id);
StateDoc.set("signupUUID", SignupUUID);
StateDoc.set("errorCode",0);
StateDoc.set("date", OpenWifi::Now());
StateDoc.set("status", "waiting for email-verification");
@@ -141,9 +128,6 @@ namespace OpenWifi {
SE.to_json(SEAnswer);
return ReturnObject(SEAnswer);
}
std::cout << __LINE__ << std::endl;
return BadRequest(RESTAPI::Errors::UserAlreadyExists);
}
@@ -161,20 +145,19 @@ namespace OpenWifi {
return NotFound();
}
if(Operation == "emailVerified") {
if(Operation == "emailVerified" && SE.statusCode==ProvObjects::SignupStatusCodes::SignupWaitingForEmail) {
std::cout << "Verified email for : " << SE.email << std::endl;
SE.info.modified = OpenWifi::Now();
SE.status = "emailVerified";
SE.statusCode = ProvObjects::SignupStatusCodes::SignupWaitingForDevice;
StorageService()->SignupDB().UpdateRecord("id", SE.info.id, SE);
Signup()->AddOutstandingSignup(SE);
Poco::JSON::Object Answer;
SE.to_json(Answer);
return ReturnObject(Answer);
}
return BadRequest("Not implemented");
}
void RESTAPI_signup_handler::DoGet() {

View File

@@ -404,6 +404,7 @@ namespace OpenWifi::ProvObjects {
field_to_json( Obj,"rrm",rrm);
field_to_json( Obj,"firmwareUpgrade",firmwareUpgrade);
field_to_json( Obj,"firmwareRCOnly",firmwareRCOnly);
field_to_json( Obj,"subscriberOnly",subscriberOnly);
}
bool DeviceConfiguration::from_json(const Poco::JSON::Object::Ptr &Obj) {
@@ -417,6 +418,7 @@ namespace OpenWifi::ProvObjects {
field_from_json( Obj,"rrm",rrm);
field_from_json( Obj,"firmwareUpgrade",firmwareUpgrade);
field_from_json( Obj,"firmwareRCOnly",firmwareRCOnly);
field_from_json( Obj,"subscriberOnly",subscriberOnly);
return true;
} catch(...) {
@@ -635,6 +637,7 @@ namespace OpenWifi::ProvObjects {
RESTAPI_utils::field_to_json( Obj,"completed", completed);
RESTAPI_utils::field_to_json( Obj,"status", status);
RESTAPI_utils::field_to_json( Obj,"error", error);
RESTAPI_utils::field_to_json( Obj,"statusCode", statusCode);
}
bool SignupEntry::from_json(const Poco::JSON::Object::Ptr &Obj) {
@@ -647,6 +650,7 @@ namespace OpenWifi::ProvObjects {
RESTAPI_utils::field_from_json( Obj,"completed", completed);
RESTAPI_utils::field_from_json( Obj,"status", status);
RESTAPI_utils::field_from_json( Obj,"error", error);
RESTAPI_utils::field_from_json( Obj,"statusCode", statusCode);
return true;
} catch(...) {

View File

@@ -264,6 +264,7 @@ namespace OpenWifi::ProvObjects {
std::string rrm;
std::string firmwareUpgrade;
bool firmwareRCOnly=false;
bool subscriberOnly=false;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);
@@ -396,6 +397,16 @@ namespace OpenWifi::ProvObjects {
bool from_json(const Poco::JSON::Object::Ptr &Obj);
};
enum SignupStatusCodes {
SignupCreated = 0 ,
SignupWaitingForEmail,
SignupWaitingForDevice,
SignupSuccess,
SignupFailure,
SignupCanceled,
SignupTimedOut
};
struct SignupEntry {
ObjectInfo info;
std::string email;
@@ -405,6 +416,7 @@ namespace OpenWifi::ProvObjects {
uint64_t completed = 0 ;
std::string status;
uint64_t error=0;
uint64_t statusCode=0;
void to_json(Poco::JSON::Object &Obj) const;
bool from_json(const Poco::JSON::Object::Ptr &Obj);

View File

@@ -51,7 +51,7 @@ namespace OpenWifi {
// get the list of outstanding stuff and see if we have gotten the device...
std::lock_guard G(Mutex_);
for(auto &[uuid,SE]:OutstandingSignups_) {
if(SE.status == "emailVerified") {
if(SE.statusCode == ProvObjects::SignupStatusCodes::SignupWaitingForDevice) {
// look for the device...
ProvObjects::InventoryTag IT;
if(StorageService()->InventoryDB().GetRecord("serialNumber",SE.serialNumber,IT)) {
@@ -75,6 +75,7 @@ namespace OpenWifi {
StorageService()->InventoryDB().UpdateRecord("id",IT.info.id,IT);
SE.status = "signup completed";
SE.statusCode = ProvObjects::SignupStatusCodes::SignupSuccess;
SE.completed = OpenWifi::Now();
SE.info.modified = OpenWifi::Now();
SE.error = 0 ;

View File

@@ -64,6 +64,21 @@ namespace OpenWifi::SDK::Sec {
}
return false;
}
bool Delete(RESTAPIHandler *client, const Types::UUID_t & Id) {
OpenAPIRequestDelete Req( uSERVICE_SECURITY,
"/api/v1/subuser/" + Id,
{},
5000);
auto StatusCode = Req.Do();
if( StatusCode == Poco::Net::HTTPResponse::HTTP_OK ||
StatusCode == Poco::Net::HTTPResponse::HTTP_NO_CONTENT ||
StatusCode == Poco::Net::HTTPResponse::HTTP_ACCEPTED) {
return true;
}
return false;
}
}
}

View File

@@ -17,6 +17,7 @@ namespace OpenWifi::SDK::Sec {
namespace Subscriber {
bool Exists(RESTAPIHandler *client, const Types::UUID_t & User);
bool Get(RESTAPIHandler *client, const Types::UUID_t & User, SecurityObjects::UserInfo & UserInfo);
bool Delete(RESTAPIHandler *client, const Types::UUID_t & User);
}
}

View File

@@ -31,7 +31,8 @@ namespace OpenWifi {
ORM::Field{"rrm",ORM::FieldType::FT_TEXT},
ORM::Field{"tags",ORM::FieldType::FT_TEXT},
ORM::Field{"firmwareUpgrade",ORM::FieldType::FT_TEXT},
ORM::Field{"firmwareRCOnly",ORM::FieldType::FT_INT}
ORM::Field{"firmwareRCOnly",ORM::FieldType::FT_INT},
ORM::Field{"subscriberOnly",ORM::FieldType::FT_BOOLEAN}
};
static ORM::IndexVec ConfigurationDB_Indexes{
@@ -41,6 +42,15 @@ namespace OpenWifi {
ORM::Indextype::ASC} } }
};
bool ConfigurationDB::Upgrade(uint32_t from, uint32_t &to) {
std::vector<std::string> Statements{
"alter table " + TableName_ + " add column subscriberOnly BOOLEAN;"
};
RunScript(Statements);
to = 2;
return true;
}
ConfigurationDB::ConfigurationDB( OpenWifi::DBType T, Poco::Data::SessionPool & P, Poco::Logger &L) :
DB(T, "configurations", ConfigurationDB_Fields, ConfigurationDB_Indexes, P, L, "cfg") {}
@@ -137,6 +147,7 @@ template<> void ORM::DB< OpenWifi::ConfigurationDBRecordType, OpenWifi::ProvO
Out.info.tags = OpenWifi::RESTAPI_utils::to_taglist(In.get<12>());
Out.firmwareUpgrade = In.get<13>();
Out.firmwareRCOnly = In.get<14>();
Out.subscriberOnly = In.get<15>();
}
template<> void ORM::DB< OpenWifi::ConfigurationDBRecordType, OpenWifi::ProvObjects::DeviceConfiguration>::Convert(const OpenWifi::ProvObjects::DeviceConfiguration &In, OpenWifi::ConfigurationDBRecordType &Out) {
@@ -155,4 +166,5 @@ template<> void ORM::DB< OpenWifi::ConfigurationDBRecordType, OpenWifi::ProvO
Out.set<12>(OpenWifi::RESTAPI_utils::to_string(In.info.tags));
Out.set<13>(In.firmwareUpgrade);
Out.set<14>(In.firmwareRCOnly);
Out.set<15>(In.subscriberOnly);
}

View File

@@ -27,13 +27,15 @@ namespace OpenWifi {
std::string,
std::string,
std::string,
uint32_t
uint32_t,
bool
> ConfigurationDBRecordType;
class ConfigurationDB : public ORM::DB<ConfigurationDBRecordType, ProvObjects::DeviceConfiguration> {
public:
ConfigurationDB( OpenWifi::DBType T, Poco::Data::SessionPool & P, Poco::Logger &L);
bool GetListOfAffectedDevices(const Types::UUID_t & ConfigUUID, Types::UUIDvec_t & DeviceSerialNumbers );
bool Upgrade(uint32_t from, uint32_t &to) override;
private:
};
}

View File

@@ -9,6 +9,7 @@
#include "StorageService.h"
#include "framework/MicroService.h"
#include "Signup.h"
#include "sdks/SDK_sec.h"
namespace OpenWifi {
@@ -26,7 +27,8 @@ namespace OpenWifi {
ORM::Field{"submitted",ORM::FieldType::FT_BIGINT},
ORM::Field{"completed",ORM::FieldType::FT_BIGINT},
ORM::Field{"status",ORM::FieldType::FT_TEXT},
ORM::Field{"error",ORM::FieldType::FT_BIGINT}
ORM::Field{"error",ORM::FieldType::FT_BIGINT},
ORM::Field{"statusCode",ORM::FieldType::FT_BIGINT}
};
const static ORM::IndexVec SignupDB_Indexes{
@@ -37,7 +39,7 @@ namespace OpenWifi {
};
SignupDB::SignupDB( OpenWifi::DBType T, Poco::Data::SessionPool & P, Poco::Logger &L) noexcept :
DB(T, "signups", SignupDB_Fields, SignupDB_Indexes, P, L, "sig") {
DB(T, "signups2", SignupDB_Fields, SignupDB_Indexes, P, L, "sig") {
}
bool SignupDB::GetIncompleteSignups(SignupDB::RecordVec &Signups) {
@@ -51,10 +53,63 @@ namespace OpenWifi {
void SignupDB::RemoveIncompleteSignups() {
try {
uint64_t Floor = OpenWifi::Now() - Signup()->GracePeriod() ;
uint64_t TooOld = OpenWifi::Now() - Signup()->LingerPeriod() ;
DeleteRecords(" completed=0 and submitted < " + std::to_string(Floor) ); // Remove incomplete entries
DeleteRecords(" completed < " + std::to_string(TooOld) ); // Remove really old stuff
Types::StringVec ToDelete, TimedOut;
uint64_t now = OpenWifi::Now();
auto F = [&](const SignupDB::RecordName &R) -> bool {
if(R.completed!=0)
return true;
if((now-R.submitted)>Signup()->LingerPeriod()) {
ToDelete.emplace_back(R.info.id);
return true;
}
if((now-R.submitted)>Signup()->GracePeriod()) {
TimedOut.push_back(R.info.id);
// delete this temporary user
SDK::Sec::Subscriber::Delete(nullptr,R.userId);
if(R.statusCode==ProvObjects::SignupStatusCodes::SignupWaitingForDevice) {
ProvObjects::InventoryTag IT;
if(StorageService()->InventoryDB().GetRecord("serialNumber",R.serialNumber,IT)) {
if(IT.devClass.empty() || IT.devClass=="any" || IT.devClass=="subscriber") {
try {
auto DeviceStatus = nlohmann::json::parse(IT.state);
if(DeviceStatus["method"]=="signup" && DeviceStatus["signupUUID"]==R.info.id) {
DeviceStatus["claimer"] = "";
DeviceStatus["claimerId"] = "";
DeviceStatus["signupUUID"] = "";
IT.subscriber = "";
IT.info.modified = Now();
IT.info.notes.push_back(SecurityObjects::NoteInfo{.created=Now(),.createdBy="signup-bot",.note="Device release from signup process."});
StorageService()->InventoryDB().UpdateRecord("serialNumber",R.serialNumber,IT);
}
} catch (...) {
}
}
}
}
return true;
}
return true;
};
Iterate(F);
for(const auto &i:ToDelete)
DeleteRecord("id",i);
for(const auto &i:TimedOut) {
SignupDB::RecordName R;
if(GetRecord("id",i,R)) {
R.statusCode=ProvObjects::SignupStatusCodes::SignupTimedOut;
R.status = "timedOut";
R.info.modified=Now();
UpdateRecord("id",i,R);
}
}
} catch (...) {
}
@@ -75,6 +130,7 @@ template<> void ORM::DB< OpenWifi::SignupDBRecordType, OpenWifi::ProvObjects:
Out.completed = In.get<10>();
Out.status = In.get<11>();
Out.error = In.get<12>();
Out.statusCode = In.get<13>();
}
template<> void ORM::DB< OpenWifi::SignupDBRecordType, OpenWifi::ProvObjects::SignupEntry>::Convert(const OpenWifi::ProvObjects::SignupEntry &In, OpenWifi::SignupDBRecordType &Out) {
@@ -91,4 +147,5 @@ template<> void ORM::DB< OpenWifi::SignupDBRecordType, OpenWifi::ProvObjects:
Out.set<10>(In.completed);
Out.set<11>(In.status);
Out.set<12>(In.error);
Out.set<13>(In.statusCode);
}

View File

@@ -21,6 +21,7 @@ namespace OpenWifi {
uint64_t,
uint64_t,
std::string,
uint64_t,
uint64_t
> SignupDBRecordType;