Commit 4c72694c by Mac Stephens

Quick fix to device update code

parent 97fe9d07
......@@ -51,13 +51,13 @@ type
procedure ClearCredentialId;
// Section: Device registration verification
procedure BeginRegistration(APhoneNumber, ADeviceType: string;
procedure BeginRegistration(APhoneNumber: string;
ASuccess: TOnCodeSentSuccess; AError: TOnDeviceError);
procedure VerifyRegistrationCode(APhoneNumber, ADeviceType, AVerificationCode: string;
procedure VerifyRegistrationCode(APhoneNumber, AVerificationCode: string;
ASuccess: TOnBeginSuccess;
AError: TOnDeviceError);
// Section: WebAuthn registration
procedure CompleteRegistration(APhoneNumber, ADeviceType, ACredentialId,
procedure CompleteRegistration(APhoneNumber, ACredentialId,
AAttestationObject, AClientDataJSON, AChallengeToken: string;
ASuccess: TOnDeviceSuccess; AError: TOnDeviceError);
......@@ -74,7 +74,7 @@ type
ASuccess: TOnLoginSuccess; AError: TOnLoginError);
// Simple-key registration and login
procedure CompleteRegistrationSimple(APhoneNumber, ADeviceType, ADeviceKey, AChallengeToken: string;
procedure CompleteRegistrationSimple(APhoneNumber, ADeviceKey, AChallengeToken: string;
ASuccess: TOnDeviceSuccess; AError: TOnDeviceError);
procedure LoginDeviceKey(ACredentialId, AChallengeToken: string;
ASuccess: TOnLoginSuccess; AError: TOnLoginError);
......@@ -218,7 +218,7 @@ end;
// ---- WebAuthn registration ----
procedure TAuthService.BeginRegistration(APhoneNumber, ADeviceType: string;
procedure TAuthService.BeginRegistration(APhoneNumber: string;
ASuccess: TOnCodeSentSuccess; AError: TOnDeviceError);
procedure OnLoad(Response: TXDataClientResponse);
......@@ -244,12 +244,12 @@ procedure TAuthService.BeginRegistration(APhoneNumber, ADeviceType: string;
begin
FClient.RawInvoke(
'IAuthService.BeginRegistration',
[APhoneNumber, ADeviceType],
[APhoneNumber],
@OnLoad, @OnError
);
end;
procedure TAuthService.VerifyRegistrationCode(APhoneNumber, ADeviceType,
procedure TAuthService.VerifyRegistrationCode(APhoneNumber,
AVerificationCode: string; ASuccess: TOnBeginSuccess;
AError: TOnDeviceError);
......@@ -278,12 +278,12 @@ procedure TAuthService.VerifyRegistrationCode(APhoneNumber, ADeviceType,
begin
FClient.RawInvoke(
'IAuthService.VerifyRegistrationCode',
[APhoneNumber, ADeviceType, AVerificationCode],
[APhoneNumber, AVerificationCode],
@OnLoad, @OnError
);
end;
procedure TAuthService.CompleteRegistration(APhoneNumber, ADeviceType, ACredentialId,
procedure TAuthService.CompleteRegistration(APhoneNumber, ACredentialId,
AAttestationObject, AClientDataJSON, AChallengeToken: string;
ASuccess: TOnDeviceSuccess; AError: TOnDeviceError);
......@@ -317,7 +317,7 @@ procedure TAuthService.CompleteRegistration(APhoneNumber, ADeviceType, ACredenti
begin
FClient.RawInvoke(
'IAuthService.CompleteRegistration',
[APhoneNumber, ADeviceType, ACredentialId, AAttestationObject, AClientDataJSON, AChallengeToken],
[APhoneNumber, ACredentialId, AAttestationObject, AClientDataJSON, AChallengeToken],
@OnLoad, @OnError
);
end;
......@@ -431,7 +431,7 @@ end;
// ---- Simple-key registration and login ----
procedure TAuthService.CompleteRegistrationSimple(APhoneNumber, ADeviceType, ADeviceKey, AChallengeToken: string;
procedure TAuthService.CompleteRegistrationSimple(APhoneNumber, ADeviceKey, AChallengeToken: string;
ASuccess: TOnDeviceSuccess; AError: TOnDeviceError);
procedure OnLoad(Response: TXDataClientResponse);
......@@ -462,7 +462,7 @@ procedure TAuthService.CompleteRegistrationSimple(APhoneNumber, ADeviceType, ADe
begin
FClient.RawInvoke(
'IAuthService.CompleteRegistrationSimple',
[APhoneNumber, ADeviceType, ADeviceKey, AChallengeToken],
[APhoneNumber, ADeviceKey, AChallengeToken],
@OnLoad, @OnError
);
end;
......
......@@ -51,13 +51,13 @@ type
procedure ClearCredentialId;
// Section: Device registration verification
procedure BeginRegistration(APhoneNumber, ADeviceType: string;
procedure BeginRegistration(APhoneNumber: string;
ASuccess: TOnCodeSentSuccess; AError: TOnDeviceError);
procedure VerifyRegistrationCode(APhoneNumber, ADeviceType, AVerificationCode: string;
procedure VerifyRegistrationCode(APhoneNumber, AVerificationCode: string;
ASuccess: TOnBeginSuccess;
AError: TOnDeviceError);
// Section: WebAuthn registration
procedure CompleteRegistration(APhoneNumber, ADeviceType, ACredentialId,
procedure CompleteRegistration(APhoneNumber, ACredentialId,
AAttestationObject, AClientDataJSON, AChallengeToken: string;
ASuccess: TOnDeviceSuccess; AError: TOnDeviceError);
......@@ -74,7 +74,7 @@ type
ASuccess: TOnLoginSuccess; AError: TOnLoginError);
// Simple-key registration and login
procedure CompleteRegistrationSimple(APhoneNumber, ADeviceType, ADeviceKey, AChallengeToken: string;
procedure CompleteRegistrationSimple(APhoneNumber, ADeviceKey, AChallengeToken: string;
ASuccess: TOnDeviceSuccess; AError: TOnDeviceError);
procedure LoginDeviceKey(ACredentialId, AChallengeToken: string;
ASuccess: TOnLoginSuccess; AError: TOnLoginError);
......@@ -246,7 +246,7 @@ end;
// ---- WebAuthn registration ----
procedure TAuthService.BeginRegistration(APhoneNumber, ADeviceType: string;
procedure TAuthService.BeginRegistration(APhoneNumber: string;
ASuccess: TOnCodeSentSuccess; AError: TOnDeviceError);
procedure OnLoad(Response: TXDataClientResponse);
......@@ -272,12 +272,12 @@ procedure TAuthService.BeginRegistration(APhoneNumber, ADeviceType: string;
begin
FClient.RawInvoke(
'IAuthService.BeginRegistration',
[APhoneNumber, ADeviceType],
[APhoneNumber],
@OnLoad, @OnError
);
end;
procedure TAuthService.VerifyRegistrationCode(APhoneNumber, ADeviceType,
procedure TAuthService.VerifyRegistrationCode(APhoneNumber,
AVerificationCode: string; ASuccess: TOnBeginSuccess;
AError: TOnDeviceError);
......@@ -306,12 +306,12 @@ procedure TAuthService.VerifyRegistrationCode(APhoneNumber, ADeviceType,
begin
FClient.RawInvoke(
'IAuthService.VerifyRegistrationCode',
[APhoneNumber, ADeviceType, AVerificationCode],
[APhoneNumber, AVerificationCode],
@OnLoad, @OnError
);
end;
procedure TAuthService.CompleteRegistration(APhoneNumber, ADeviceType, ACredentialId,
procedure TAuthService.CompleteRegistration(APhoneNumber, ACredentialId,
AAttestationObject, AClientDataJSON, AChallengeToken: string;
ASuccess: TOnDeviceSuccess; AError: TOnDeviceError);
......@@ -345,7 +345,7 @@ procedure TAuthService.CompleteRegistration(APhoneNumber, ADeviceType, ACredenti
begin
FClient.RawInvoke(
'IAuthService.CompleteRegistration',
[APhoneNumber, ADeviceType, ACredentialId, AAttestationObject, AClientDataJSON, AChallengeToken],
[APhoneNumber, ACredentialId, AAttestationObject, AClientDataJSON, AChallengeToken],
@OnLoad, @OnError
);
end;
......@@ -459,7 +459,7 @@ end;
// ---- Simple-key registration and login ----
procedure TAuthService.CompleteRegistrationSimple(APhoneNumber, ADeviceType, ADeviceKey, AChallengeToken: string;
procedure TAuthService.CompleteRegistrationSimple(APhoneNumber, ADeviceKey, AChallengeToken: string;
ASuccess: TOnDeviceSuccess; AError: TOnDeviceError);
procedure OnLoad(Response: TXDataClientResponse);
......@@ -490,7 +490,7 @@ procedure TAuthService.CompleteRegistrationSimple(APhoneNumber, ADeviceType, ADe
begin
FClient.RawInvoke(
'IAuthService.CompleteRegistrationSimple',
[APhoneNumber, ADeviceType, ADeviceKey, AChallengeToken],
[APhoneNumber, ADeviceKey, AChallengeToken],
@OnLoad, @OnError
);
end;
......
......@@ -14,17 +14,17 @@ type
// Note: A supplied connection is borrowed and must outlive this store.
procedure UseConnection(AConnection: TUniConnection); virtual; abstract;
property Connection: TUniConnection read GetConnection;
function PendingDevice(PhoneNumber: string; DeviceType: string): TDataSet; virtual; abstract;
function SetVerificationCode(Code: string; PhoneNumber: string; DeviceType: string): Int64; virtual; abstract;
function ConsumeVerificationCode(PhoneNumber: string; Code: string; DeviceType: string): Int64; virtual; abstract;
function ActivateWebAuthnDevice(CredentialId: string; UserAgent: string; PublicKeyX: TBytes; PublicKeyY: TBytes; PublicKeyAlg: Integer; SignCount: Integer; PhoneNumber: string; DeviceType: string): Int64; virtual; abstract;
function PendingDevice(PhoneNumber: string): TDataSet; virtual; abstract;
function SetVerificationCode(Code: string; PhoneNumber: string): Int64; virtual; abstract;
function ConsumeVerificationCode(PhoneNumber: string; Code: string): Int64; virtual; abstract;
function ActivateWebAuthnDevice(CredentialId: string; UserAgent: string; PublicKeyX: TBytes; PublicKeyY: TBytes; PublicKeyAlg: Integer; SignCount: Integer; PhoneNumber: string): Int64; virtual; abstract;
function UnrevokedDeviceUser(CredentialId: string): TDataSet; virtual; abstract;
function ActiveDeviceUser(CredentialId: string): TDataSet; virtual; abstract;
function UnrevokedDeviceKey(CredentialId: string): TDataSet; virtual; abstract;
function UpdateSignCount(SignCount: Integer; CredentialId: string): Int64; virtual; abstract;
function SaveDeviceUser(Username: string; Agency: string; CredentialId: string): Int64; virtual; abstract;
function ActiveDeviceKey(CredentialId: string): TDataSet; virtual; abstract;
function ActivateSimpleDevice(CredentialId: string; UserAgent: string; PhoneNumber: string; DeviceType: string): Int64; virtual; abstract;
function ActivateSimpleDevice(CredentialId: string; UserAgent: string; PhoneNumber: string): Int64; virtual; abstract;
function ActiveSimpleDeviceUser(CredentialId: string): TDataSet; virtual; abstract;
function ActiveSimpleDevice(CredentialId: string): TDataSet; virtual; abstract;
function DeviceStatus(CredentialId: string): TDataSet; virtual; abstract;
......@@ -32,7 +32,7 @@ type
function RevokeDevice(RevokedBy: string; CredentialId: string): Int64; virtual; abstract;
function UnrevokeDevice(CredentialId: string): Int64; virtual; abstract;
function DeviceNameExists(DeviceName: string): Boolean; virtual; abstract;
function PendingPhone(PhoneNumber: string; DeviceType: string): TDataSet; virtual; abstract;
function PendingPhone(PhoneNumber: string): TDataSet; virtual; abstract;
function AddPendingDevice(DeviceName: string; DeviceType: string; PhoneNumber: string): Int64; virtual; abstract;
function DeleteDevice(DeviceId: Integer): Int64; virtual; abstract;
function ReserveRedeemCode(PhoneNumber: string; out Code: string): Boolean; virtual; abstract;
......
......@@ -18,8 +18,7 @@ object OracleDeviceDatabase: TOracleDeviceDatabase
'SELECT ID, DEVICE_NAME'
'FROM DEVICE_REGISTRATIONS'
'WHERE PHONE_NUMBER = :PHONE'
' AND STATUS = ''pending'''
' AND LOWER(TRIM(DEVICE_TYPE)) = :TYPE')
' AND STATUS = ''pending''')
ReadOnly = True
Active = False
Left = 60
......@@ -27,11 +26,6 @@ object OracleDeviceDatabase: TOracleDeviceDatabase
ParamData = <
item
DataType = ftString
Name = 'TYPE'
ParamType = ptInput
end
item
DataType = ftString
Name = 'PHONE'
ParamType = ptInput
end>
......@@ -42,19 +36,13 @@ object OracleDeviceDatabase: TOracleDeviceDatabase
'UPDATE DEVICE_REGISTRATIONS'
'SET VERIFICATION_CODE = :CODE, VERIFICATION_EXPIRES_AT = SYSTIMESTAMP + INTERVAL ''5'' MINUTE'
'WHERE PHONE_NUMBER = :PHONE'
' AND STATUS = ''pending'''
' AND LOWER(TRIM(DEVICE_TYPE)) = :TYPE')
' AND STATUS = ''pending''')
Active = False
Left = 250
Top = 110
ParamData = <
item
DataType = ftString
Name = 'TYPE'
ParamType = ptInput
end
item
DataType = ftString
Name = 'CODE'
ParamType = ptInput
end
......@@ -72,19 +60,13 @@ object OracleDeviceDatabase: TOracleDeviceDatabase
'WHERE PHONE_NUMBER = :PHONE'
' AND STATUS = ''pending'''
' AND VERIFICATION_CODE = :CODE'
' AND VERIFICATION_EXPIRES_AT > SYSTIMESTAMP'
' AND LOWER(TRIM(DEVICE_TYPE)) = :TYPE')
' AND VERIFICATION_EXPIRES_AT > SYSTIMESTAMP')
Active = False
Left = 630
Top = 110
ParamData = <
item
DataType = ftString
Name = 'TYPE'
ParamType = ptInput
end
item
DataType = ftString
Name = 'PHONE'
ParamType = ptInput
end
......@@ -100,19 +82,13 @@ object OracleDeviceDatabase: TOracleDeviceDatabase
'UPDATE DEVICE_REGISTRATIONS'
'SET CREDENTIAL_ID = :CID, USER_AGENT = :AGENT, PUBLIC_KEY_X = :KEYX, PUBLIC_KEY_Y = :KEYY, PUBLIC_KEY_ALG = :ALG, SIGN_COUNT = :CNT, VERIFICATION_CODE = NULL, VERIFICATION_EXPIRES_AT = NULL, STATUS = ''active'', REGISTERED_AT = SYSTIMESTAMP'
'WHERE PHONE_NUMBER = :PHONE'
' AND STATUS = ''pending'''
' AND LOWER(TRIM(DEVICE_TYPE)) = :TYPE')
' AND STATUS = ''pending''')
Active = False
Left = 820
Top = 110
ParamData = <
item
DataType = ftString
Name = 'TYPE'
ParamType = ptInput
end
item
DataType = ftString
Name = 'CID'
ParamType = ptInput
end
......@@ -274,19 +250,13 @@ object OracleDeviceDatabase: TOracleDeviceDatabase
'UPDATE DEVICE_REGISTRATIONS'
'SET CREDENTIAL_ID = :CID, USER_AGENT = :AGENT, KEY_TYPE = ''simple'', VERIFICATION_CODE = NULL, VERIFICATION_EXPIRES_AT = NULL, STATUS = ''active'', REGISTERED_AT = SYSTIMESTAMP'
'WHERE PHONE_NUMBER = :PHONE'
' AND STATUS = ''pending'''
' AND LOWER(TRIM(DEVICE_TYPE)) = :TYPE')
' AND STATUS = ''pending''')
Active = False
Left = 250
Top = 330
ParamData = <
item
DataType = ftString
Name = 'TYPE'
ParamType = ptInput
end
item
DataType = ftString
Name = 'CID'
ParamType = ptInput
end
......@@ -428,8 +398,7 @@ object OracleDeviceDatabase: TOracleDeviceDatabase
'SELECT ID'
'FROM DEVICE_REGISTRATIONS'
'WHERE PHONE_NUMBER = :PHONE'
' AND STATUS = ''pending'''
' AND LOWER(TRIM(DEVICE_TYPE)) = :TYPE')
' AND STATUS = ''pending''')
ReadOnly = True
Active = False
Left = 630
......@@ -437,11 +406,6 @@ object OracleDeviceDatabase: TOracleDeviceDatabase
ParamData = <
item
DataType = ftString
Name = 'TYPE'
ParamType = ptInput
end
item
DataType = ftString
Name = 'PHONE'
ParamType = ptInput
end>
......
......@@ -40,17 +40,17 @@ type
function GetConnection: TUniConnection; override;
public
procedure UseConnection(AConnection: TUniConnection); override;
function PendingDevice(PhoneNumber: string; DeviceType: string): TDataSet; override;
function SetVerificationCode(Code: string; PhoneNumber: string; DeviceType: string): Int64; override;
function ConsumeVerificationCode(PhoneNumber: string; Code: string; DeviceType: string): Int64; override;
function ActivateWebAuthnDevice(CredentialId: string; UserAgent: string; PublicKeyX: TBytes; PublicKeyY: TBytes; PublicKeyAlg: Integer; SignCount: Integer; PhoneNumber: string; DeviceType: string): Int64; override;
function PendingDevice(PhoneNumber: string): TDataSet; override;
function SetVerificationCode(Code: string; PhoneNumber: string): Int64; override;
function ConsumeVerificationCode(PhoneNumber: string; Code: string): Int64; override;
function ActivateWebAuthnDevice(CredentialId: string; UserAgent: string; PublicKeyX: TBytes; PublicKeyY: TBytes; PublicKeyAlg: Integer; SignCount: Integer; PhoneNumber: string): Int64; override;
function UnrevokedDeviceUser(CredentialId: string): TDataSet; override;
function ActiveDeviceUser(CredentialId: string): TDataSet; override;
function UnrevokedDeviceKey(CredentialId: string): TDataSet; override;
function UpdateSignCount(SignCount: Integer; CredentialId: string): Int64; override;
function SaveDeviceUser(Username: string; Agency: string; CredentialId: string): Int64; override;
function ActiveDeviceKey(CredentialId: string): TDataSet; override;
function ActivateSimpleDevice(CredentialId: string; UserAgent: string; PhoneNumber: string; DeviceType: string): Int64; override;
function ActivateSimpleDevice(CredentialId: string; UserAgent: string; PhoneNumber: string): Int64; override;
function ActiveSimpleDeviceUser(CredentialId: string): TDataSet; override;
function ActiveSimpleDevice(CredentialId: string): TDataSet; override;
function DeviceStatus(CredentialId: string): TDataSet; override;
......@@ -58,7 +58,7 @@ type
function RevokeDevice(RevokedBy: string; CredentialId: string): Int64; override;
function UnrevokeDevice(CredentialId: string): Int64; override;
function DeviceNameExists(DeviceName: string): Boolean; override;
function PendingPhone(PhoneNumber: string; DeviceType: string): TDataSet; override;
function PendingPhone(PhoneNumber: string): TDataSet; override;
function AddPendingDevice(DeviceName: string; DeviceType: string; PhoneNumber: string): Int64; override;
function DeleteDevice(DeviceId: Integer): Int64; override;
function ReserveRedeemCode(PhoneNumber: string; out Code: string): Boolean; override;
......@@ -93,36 +93,33 @@ begin
TUniQuery(Components[i]).Connection := Connection;
end;
function TOracleDeviceDatabase.PendingDevice(PhoneNumber: string; DeviceType: string): TDataSet;
function TOracleDeviceDatabase.PendingDevice(PhoneNumber: string): TDataSet;
begin
uqPendingDevice.Close;
uqPendingDevice.ParamByName('PHONE').AsString := PhoneNumber;
uqPendingDevice.ParamByName('TYPE').AsString := DeviceType;
uqPendingDevice.Open;
Result := uqPendingDevice;
end;
function TOracleDeviceDatabase.SetVerificationCode(Code: string; PhoneNumber: string; DeviceType: string): Int64;
function TOracleDeviceDatabase.SetVerificationCode(Code: string; PhoneNumber: string): Int64;
begin
uqSetVerificationCode.Close;
uqSetVerificationCode.ParamByName('CODE').AsString := Code;
uqSetVerificationCode.ParamByName('PHONE').AsString := PhoneNumber;
uqSetVerificationCode.ParamByName('TYPE').AsString := DeviceType;
uqSetVerificationCode.ExecSQL;
Result := uqSetVerificationCode.RowsAffected;
end;
function TOracleDeviceDatabase.ConsumeVerificationCode(PhoneNumber: string; Code: string; DeviceType: string): Int64;
function TOracleDeviceDatabase.ConsumeVerificationCode(PhoneNumber: string; Code: string): Int64;
begin
uqConsumeVerificationCode.Close;
uqConsumeVerificationCode.ParamByName('PHONE').AsString := PhoneNumber;
uqConsumeVerificationCode.ParamByName('TYPE').AsString := DeviceType;
uqConsumeVerificationCode.ParamByName('CODE').AsString := Code;
uqConsumeVerificationCode.ExecSQL;
Result := uqConsumeVerificationCode.RowsAffected;
end;
function TOracleDeviceDatabase.ActivateWebAuthnDevice(CredentialId: string; UserAgent: string; PublicKeyX: TBytes; PublicKeyY: TBytes; PublicKeyAlg: Integer; SignCount: Integer; PhoneNumber: string; DeviceType: string): Int64;
function TOracleDeviceDatabase.ActivateWebAuthnDevice(CredentialId: string; UserAgent: string; PublicKeyX: TBytes; PublicKeyY: TBytes; PublicKeyAlg: Integer; SignCount: Integer; PhoneNumber: string): Int64;
begin
uqActivateWebAuthnDevice.Close;
uqActivateWebAuthnDevice.ParamByName('CID').AsString := CredentialId;
......@@ -132,7 +129,6 @@ begin
uqActivateWebAuthnDevice.ParamByName('ALG').AsInteger := PublicKeyAlg;
uqActivateWebAuthnDevice.ParamByName('CNT').AsInteger := SignCount;
uqActivateWebAuthnDevice.ParamByName('PHONE').AsString := PhoneNumber;
uqActivateWebAuthnDevice.ParamByName('TYPE').AsString := DeviceType;
uqActivateWebAuthnDevice.ExecSQL;
Result := uqActivateWebAuthnDevice.RowsAffected;
end;
......@@ -188,13 +184,12 @@ begin
Result := uqActiveDeviceKey;
end;
function TOracleDeviceDatabase.ActivateSimpleDevice(CredentialId: string; UserAgent: string; PhoneNumber: string; DeviceType: string): Int64;
function TOracleDeviceDatabase.ActivateSimpleDevice(CredentialId: string; UserAgent: string; PhoneNumber: string): Int64;
begin
uqActivateSimpleDevice.Close;
uqActivateSimpleDevice.ParamByName('CID').AsString := CredentialId;
uqActivateSimpleDevice.ParamByName('AGENT').AsString := UserAgent;
uqActivateSimpleDevice.ParamByName('PHONE').AsString := PhoneNumber;
uqActivateSimpleDevice.ParamByName('TYPE').AsString := DeviceType;
uqActivateSimpleDevice.ExecSQL;
Result := uqActivateSimpleDevice.RowsAffected;
end;
......@@ -259,11 +254,10 @@ begin
end;
end;
function TOracleDeviceDatabase.PendingPhone(PhoneNumber: string; DeviceType: string): TDataSet;
function TOracleDeviceDatabase.PendingPhone(PhoneNumber: string): TDataSet;
begin
uqPendingPhone.Close;
uqPendingPhone.ParamByName('PHONE').AsString := PhoneNumber;
uqPendingPhone.ParamByName('TYPE').AsString := DeviceType;
uqPendingPhone.Open;
Result := uqPendingPhone;
end;
......
......@@ -16,18 +16,12 @@ object PostgreSQLDeviceDatabase: TPostgreSQLDeviceDatabase
SQL.Strings = (
'SELECT id, device_name FROM lems.device_registrations WHERE phon' +
'e_number = :PHONE AND status = '#39'pending'#39
' AND LOWER(TRIM(DEVICE_TYPE)) = :TYPE')
'e_number = :PHONE AND status = '#39'pending'#39)
Left = 60
Top = 110
ParamData = <
item
DataType = ftString
Name = 'TYPE'
ParamType = ptInput
end
item
DataType = ftString
Name = 'PHONE'
ParamType = ptInput
Value = nil
......@@ -39,18 +33,12 @@ object PostgreSQLDeviceDatabase: TPostgreSQLDeviceDatabase
'UPDATE lems.device_registrations SET verification_code = :CODE, ' +
' verification_expires_at = NOW() + INTERVAL '#39'5 minutes'#39' WHERE' +
' phone_number = :PHONE AND status = '#39'pending'#39
' AND LOWER(TRIM(DEVICE_TYPE)) = :TYPE')
' phone_number = :PHONE AND status = '#39'pending'#39)
Left = 188
Top = 178
ParamData = <
item
DataType = ftString
Name = 'TYPE'
ParamType = ptInput
end
item
DataType = ftString
Name = 'CODE'
ParamType = ptInput
Value = nil
......@@ -69,18 +57,12 @@ object PostgreSQLDeviceDatabase: TPostgreSQLDeviceDatabase
'UPDATE lems.device_registrations SET verification_code = NULL, v' +
'erification_expires_at = NULL WHERE phone_number = :PHONE AND st' +
'atus = '#39'pending'#39' AND verification_code = :CODE AND verification_' +
'expires_at > NOW()'
' AND LOWER(TRIM(DEVICE_TYPE)) = :TYPE')
'expires_at > NOW()')
Left = 502
Top = 130
ParamData = <
item
DataType = ftString
Name = 'TYPE'
ParamType = ptInput
end
item
DataType = ftString
Name = 'PHONE'
ParamType = ptInput
Value = nil
......@@ -101,18 +83,12 @@ object PostgreSQLDeviceDatabase: TPostgreSQLDeviceDatabase
' public_key_alg = :ALG, sign_count = :CNT, verification_c' +
'ode = NULL, verification_expires_at = NULL, status = '#39'active' +
#39', registered_at = NOW() WHERE phone_number = :PHONE AND status ' +
'= '#39'pending'#39
' AND LOWER(TRIM(DEVICE_TYPE)) = :TYPE')
'= '#39'pending'#39)
Left = 618
Top = 164
ParamData = <
item
DataType = ftString
Name = 'TYPE'
ParamType = ptInput
end
item
DataType = ftString
Name = 'CID'
ParamType = ptInput
Value = nil
......@@ -279,18 +255,12 @@ object PostgreSQLDeviceDatabase: TPostgreSQLDeviceDatabase
'agent = :AGENT, key_type = '#39'simple'#39', verification_code =' +
' NULL, verification_expires_at = NULL, status = '#39'active'#39', re' +
'gistered_at = NOW() WHERE phone_number = :PHONE AND status = '#39'pe' +
'nding'#39
' AND LOWER(TRIM(DEVICE_TYPE)) = :TYPE')
'nding'#39)
Left = 190
Top = 364
ParamData = <
item
DataType = ftString
Name = 'TYPE'
ParamType = ptInput
end
item
DataType = ftString
Name = 'CID'
ParamType = ptInput
Value = nil
......@@ -429,18 +399,12 @@ object PostgreSQLDeviceDatabase: TPostgreSQLDeviceDatabase
SQL.Strings = (
'SELECT id FROM lems.device_registrations WHERE phone_number = :P' +
'HONE AND status = '#39'pending'#39
' AND LOWER(TRIM(DEVICE_TYPE)) = :TYPE')
'HONE AND status = '#39'pending'#39)
Left = 470
Top = 458
ParamData = <
item
DataType = ftString
Name = 'TYPE'
ParamType = ptInput
end
item
DataType = ftString
Name = 'PHONE'
ParamType = ptInput
Value = nil
......
......@@ -41,17 +41,17 @@ type
function GetConnection: TUniConnection; override;
public
procedure UseConnection(AConnection: TUniConnection); override;
function PendingDevice(PhoneNumber: string; DeviceType: string): TDataSet; override;
function SetVerificationCode(Code: string; PhoneNumber: string; DeviceType: string): Int64; override;
function ConsumeVerificationCode(PhoneNumber: string; Code: string; DeviceType: string): Int64; override;
function ActivateWebAuthnDevice(CredentialId: string; UserAgent: string; PublicKeyX: TBytes; PublicKeyY: TBytes; PublicKeyAlg: Integer; SignCount: Integer; PhoneNumber: string; DeviceType: string): Int64; override;
function PendingDevice(PhoneNumber: string): TDataSet; override;
function SetVerificationCode(Code: string; PhoneNumber: string): Int64; override;
function ConsumeVerificationCode(PhoneNumber: string; Code: string): Int64; override;
function ActivateWebAuthnDevice(CredentialId: string; UserAgent: string; PublicKeyX: TBytes; PublicKeyY: TBytes; PublicKeyAlg: Integer; SignCount: Integer; PhoneNumber: string): Int64; override;
function UnrevokedDeviceUser(CredentialId: string): TDataSet; override;
function ActiveDeviceUser(CredentialId: string): TDataSet; override;
function UnrevokedDeviceKey(CredentialId: string): TDataSet; override;
function UpdateSignCount(SignCount: Integer; CredentialId: string): Int64; override;
function SaveDeviceUser(Username: string; Agency: string; CredentialId: string): Int64; override;
function ActiveDeviceKey(CredentialId: string): TDataSet; override;
function ActivateSimpleDevice(CredentialId: string; UserAgent: string; PhoneNumber: string; DeviceType: string): Int64; override;
function ActivateSimpleDevice(CredentialId: string; UserAgent: string; PhoneNumber: string): Int64; override;
function ActiveSimpleDeviceUser(CredentialId: string): TDataSet; override;
function ActiveSimpleDevice(CredentialId: string): TDataSet; override;
function DeviceStatus(CredentialId: string): TDataSet; override;
......@@ -59,7 +59,7 @@ type
function RevokeDevice(RevokedBy: string; CredentialId: string): Int64; override;
function UnrevokeDevice(CredentialId: string): Int64; override;
function DeviceNameExists(DeviceName: string): Boolean; override;
function PendingPhone(PhoneNumber: string; DeviceType: string): TDataSet; override;
function PendingPhone(PhoneNumber: string): TDataSet; override;
function AddPendingDevice(DeviceName: string; DeviceType: string; PhoneNumber: string): Int64; override;
function DeleteDevice(DeviceId: Integer): Int64; override;
function ReserveRedeemCode(PhoneNumber: string; out Code: string): Boolean; override;
......@@ -94,36 +94,33 @@ begin
TUniQuery(Components[i]).Connection := Connection;
end;
function TPostgreSQLDeviceDatabase.PendingDevice(PhoneNumber: string; DeviceType: string): TDataSet;
function TPostgreSQLDeviceDatabase.PendingDevice(PhoneNumber: string): TDataSet;
begin
uqPendingDevice.Close;
uqPendingDevice.ParamByName('PHONE').AsString := PhoneNumber;
uqPendingDevice.ParamByName('TYPE').AsString := DeviceType;
uqPendingDevice.Open;
Result := uqPendingDevice;
end;
function TPostgreSQLDeviceDatabase.SetVerificationCode(Code: string; PhoneNumber: string; DeviceType: string): Int64;
function TPostgreSQLDeviceDatabase.SetVerificationCode(Code: string; PhoneNumber: string): Int64;
begin
uqSetVerificationCode.Close;
uqSetVerificationCode.ParamByName('CODE').AsString := Code;
uqSetVerificationCode.ParamByName('PHONE').AsString := PhoneNumber;
uqSetVerificationCode.ParamByName('TYPE').AsString := DeviceType;
uqSetVerificationCode.ExecSQL;
Result := uqSetVerificationCode.RowsAffected;
end;
function TPostgreSQLDeviceDatabase.ConsumeVerificationCode(PhoneNumber: string; Code: string; DeviceType: string): Int64;
function TPostgreSQLDeviceDatabase.ConsumeVerificationCode(PhoneNumber: string; Code: string): Int64;
begin
uqConsumeVerificationCode.Close;
uqConsumeVerificationCode.ParamByName('PHONE').AsString := PhoneNumber;
uqConsumeVerificationCode.ParamByName('TYPE').AsString := DeviceType;
uqConsumeVerificationCode.ParamByName('CODE').AsString := Code;
uqConsumeVerificationCode.ExecSQL;
Result := uqConsumeVerificationCode.RowsAffected;
end;
function TPostgreSQLDeviceDatabase.ActivateWebAuthnDevice(CredentialId: string; UserAgent: string; PublicKeyX: TBytes; PublicKeyY: TBytes; PublicKeyAlg: Integer; SignCount: Integer; PhoneNumber: string; DeviceType: string): Int64;
function TPostgreSQLDeviceDatabase.ActivateWebAuthnDevice(CredentialId: string; UserAgent: string; PublicKeyX: TBytes; PublicKeyY: TBytes; PublicKeyAlg: Integer; SignCount: Integer; PhoneNumber: string): Int64;
begin
uqActivateWebAuthnDevice.Close;
uqActivateWebAuthnDevice.ParamByName('CID').AsString := CredentialId;
......@@ -133,7 +130,6 @@ begin
uqActivateWebAuthnDevice.ParamByName('ALG').AsInteger := PublicKeyAlg;
uqActivateWebAuthnDevice.ParamByName('CNT').AsInteger := SignCount;
uqActivateWebAuthnDevice.ParamByName('PHONE').AsString := PhoneNumber;
uqActivateWebAuthnDevice.ParamByName('TYPE').AsString := DeviceType;
uqActivateWebAuthnDevice.ExecSQL;
Result := uqActivateWebAuthnDevice.RowsAffected;
end;
......@@ -189,13 +185,12 @@ begin
Result := uqActiveDeviceKey;
end;
function TPostgreSQLDeviceDatabase.ActivateSimpleDevice(CredentialId: string; UserAgent: string; PhoneNumber: string; DeviceType: string): Int64;
function TPostgreSQLDeviceDatabase.ActivateSimpleDevice(CredentialId: string; UserAgent: string; PhoneNumber: string): Int64;
begin
uqActivateSimpleDevice.Close;
uqActivateSimpleDevice.ParamByName('CID').AsString := CredentialId;
uqActivateSimpleDevice.ParamByName('AGENT').AsString := UserAgent;
uqActivateSimpleDevice.ParamByName('PHONE').AsString := PhoneNumber;
uqActivateSimpleDevice.ParamByName('TYPE').AsString := DeviceType;
uqActivateSimpleDevice.ExecSQL;
Result := uqActivateSimpleDevice.RowsAffected;
end;
......@@ -260,11 +255,10 @@ begin
end;
end;
function TPostgreSQLDeviceDatabase.PendingPhone(PhoneNumber: string; DeviceType: string): TDataSet;
function TPostgreSQLDeviceDatabase.PendingPhone(PhoneNumber: string): TDataSet;
begin
uqPendingPhone.Close;
uqPendingPhone.ParamByName('PHONE').AsString := PhoneNumber;
uqPendingPhone.ParamByName('TYPE').AsString := DeviceType;
uqPendingPhone.Open;
Result := uqPendingPhone;
end;
......
......@@ -533,13 +533,13 @@ begin
Exit;
end;
// Note: A phone number can have one pending registration per device type.
q := store.PendingPhone(normalizedPhone, normalizedDeviceType);
// Reject if a pending entry with this phone already exists
q := store.PendingPhone(normalizedPhone);
if not q.IsEmpty then
begin
q.Close;
Result.AddPair('status', 'error');
Result.AddPair('message', 'A pending entry for that phone number and device type already exists.');
Result.AddPair('message', 'A pending entry for that phone number already exists.');
Exit;
end;
q.Close;
......
......@@ -79,12 +79,12 @@ type
function VerifyVersion(ClientVersion: string): TJSONObject;
// Section: Device registration step 1 checks phone pre-auth and sends an SMS code
function BeginRegistration(const PhoneNumber, DeviceType: string): TJSONObject;
function BeginRegistration(const PhoneNumber: string): TJSONObject;
// Section: Device registration step 2 verifies the SMS code and returns a challenge
function VerifyRegistrationCode(const PhoneNumber, DeviceType,
function VerifyRegistrationCode(const PhoneNumber,
VerificationCode: string): TJSONObject;
// Section: WebAuthn registration verifies the credential and activates the pending row
function CompleteRegistration(const PhoneNumber, DeviceType, CredentialId,
function CompleteRegistration(const PhoneNumber, CredentialId,
AttestationObject, ClientDataJSON,
ChallengeToken: string): TJSONObject;
// WebAuthn authentication challenge — called before Login
......@@ -96,7 +96,7 @@ type
AuthenticatorData, ClientDataJSON,
Signature: string): string;
// Simple-key registration — client generates key, no crypto verification
function CompleteRegistrationSimple(const PhoneNumber, DeviceType, DeviceKey,
function CompleteRegistrationSimple(const PhoneNumber, DeviceKey,
ChallengeToken: string): TJSONObject;
// Simple-key auto-login — verifies challenge token + credential ownership
function LoginDeviceKey(const CredentialId, ChallengeToken: string): string;
......
......@@ -41,16 +41,16 @@ type
destructor Destroy; override;
function GetAgencieslist(): TAgenciesList;
function GetAgencyConfiglist: TAgencyConfigList;
function BeginRegistration(const PhoneNumber, DeviceType: string): TJSONObject;
function VerifyRegistrationCode(const PhoneNumber, DeviceType,
function BeginRegistration(const PhoneNumber: string): TJSONObject;
function VerifyRegistrationCode(const PhoneNumber,
VerificationCode: string): TJSONObject;
function CompleteRegistration(const PhoneNumber, DeviceType, CredentialId, AttestationObject, ClientDataJSON, ChallengeToken: string): TJSONObject;
function CompleteRegistration(const PhoneNumber, CredentialId, AttestationObject, ClientDataJSON, ChallengeToken: string): TJSONObject;
function BeginAuthentication(const CredentialId: string): TJSONObject;
function GetDeviceUser(const CredentialId: string): TJSONObject;
function LoginAutomatic(const CredentialId, ChallengeToken,
AuthenticatorData, ClientDataJSON,
Signature: string): string;
function CompleteRegistrationSimple(const PhoneNumber, DeviceType, DeviceKey,
function CompleteRegistrationSimple(const PhoneNumber, DeviceKey,
ChallengeToken: string): TJSONObject;
function LoginDeviceKey(const CredentialId, ChallengeToken: string): string;
function LoginPasswordAndSimpleKey(const User, Password, Agency,
......@@ -257,7 +257,7 @@ end;
// BeginRegistration
// ---------------------------------------------------------------------------
function TAuthService.BeginRegistration(const PhoneNumber, DeviceType: string): TJSONObject;
function TAuthService.BeginRegistration(const PhoneNumber: string): TJSONObject;
var
affectedRows: Int64;
code, normalizedPhone, deviceName: string;
......@@ -287,24 +287,14 @@ begin
end;
end;
if (not SameText(Trim(DeviceType), 'iphone')) and
(not SameText(Trim(DeviceType), 'android')) and
(not SameText(Trim(DeviceType), 'browser')) and
(not SameText(Trim(DeviceType), 'other')) then
begin
Result.AddPair('status', 'error');
Result.AddPair('message', 'Please select a valid device type.');
Exit;
end;
// Verify phone number was pre-authorized by admin
q := FDeviceStore.PendingDevice(normalizedPhone, LowerCase(Trim(DeviceType)));
q := FDeviceStore.PendingDevice(normalizedPhone);
if q.IsEmpty then
begin
q.Close;
Logger.Log(2, 'BeginRegistration - phone not pre-authorized: "' + normalizedPhone + '"');
Result.AddPair('status', 'error');
Result.AddPair('message', 'No pending registration matches that phone number and device type. Contact your administrator.');
Result.AddPair('message', 'Phone number not recognized. Contact your administrator.');
Exit;
end;
deviceId := q.FieldByName('id').AsInteger;
......@@ -330,11 +320,11 @@ begin
end;
// Note: Persist the code only after the SMS provider accepts the message.
affectedRows := FDeviceStore.SetVerificationCode(code, normalizedPhone, LowerCase(Trim(DeviceType)));
affectedRows := FDeviceStore.SetVerificationCode(code, normalizedPhone);
if affectedRows = 0 then
begin
Result.AddPair('status', 'error');
Result.AddPair('message', 'No pending registration matches that phone number and device type. Contact your administrator.');
Result.AddPair('message', 'Phone number not recognized. Contact your administrator.');
Exit;
end;
......@@ -346,7 +336,7 @@ begin
Logger.Log(3, '---TAuthService.BeginRegistration End');
end;
function TAuthService.VerifyRegistrationCode(const PhoneNumber, DeviceType,
function TAuthService.VerifyRegistrationCode(const PhoneNumber,
VerificationCode: string): TJSONObject;
var
affectedRows: Int64;
......@@ -370,7 +360,7 @@ begin
verificationValid := False;
if Length(Trim(VerificationCode)) = 6 then
begin
affectedRows := FDeviceStore.ConsumeVerificationCode(normalizedPhone, Trim(VerificationCode), LowerCase(Trim(DeviceType)));
affectedRows := FDeviceStore.ConsumeVerificationCode(normalizedPhone, Trim(VerificationCode));
verificationValid := affectedRows > 0;
end;
......@@ -383,7 +373,7 @@ begin
Exit;
end;
token := MakeChallengeToken('reg-' + normalizedPhone + '-' + LowerCase(Trim(DeviceType)));
token := MakeChallengeToken('reg-' + normalizedPhone);
challengeB64 := token.Split([':'], 4)[0];
Result.AddPair('status', 'ok');
......@@ -399,7 +389,7 @@ end;
// CompleteRegistration
// ---------------------------------------------------------------------------
function TAuthService.CompleteRegistration(const PhoneNumber, DeviceType, CredentialId,
function TAuthService.CompleteRegistration(const PhoneNumber, CredentialId,
AttestationObject, ClientDataJSON, ChallengeToken: string): TJSONObject;
var
affectedRows: Int64;
......@@ -434,7 +424,7 @@ begin
// 1. Verify challenge token
if not VerifyChallengeToken(ChallengeToken,
'reg-' + normalizedPhone + '-' + LowerCase(Trim(DeviceType)), challengeB64) then
'reg-' + normalizedPhone, challengeB64) then
begin
Result.AddPair('status', 'error');
Result.AddPair('message', 'Invalid or expired registration challenge.');
......@@ -557,7 +547,7 @@ begin
if ctx <> nil then
userAgent := ctx.Request.Headers.Get('User-Agent');
affectedRows := FDeviceStore.ActivateWebAuthnDevice(Trim(CredentialId), userAgent, pubKeyX, pubKeyY, pubKeyAlg, Integer(signCount), normalizedPhone, LowerCase(Trim(DeviceType)));
affectedRows := FDeviceStore.ActivateWebAuthnDevice(Trim(CredentialId), userAgent, pubKeyX, pubKeyY, pubKeyAlg, Integer(signCount), normalizedPhone);
if affectedRows = 0 then
begin
......@@ -1008,7 +998,7 @@ end;
// CompleteRegistrationSimple — client-generated key, no crypto verification
// ---------------------------------------------------------------------------
function TAuthService.CompleteRegistrationSimple(const PhoneNumber, DeviceType, DeviceKey,
function TAuthService.CompleteRegistrationSimple(const PhoneNumber, DeviceKey,
ChallengeToken: string): TJSONObject;
var
affectedRows: Int64;
......@@ -1031,7 +1021,7 @@ begin
end;
if not VerifyChallengeToken(ChallengeToken,
'reg-' + normalizedPhone + '-' + LowerCase(Trim(DeviceType)), challengeB64) then
'reg-' + normalizedPhone, challengeB64) then
begin
Result.AddPair('status', 'error');
Result.AddPair('message', 'Invalid or expired registration challenge.');
......@@ -1050,7 +1040,7 @@ begin
if ctx <> nil then
userAgent := ctx.Request.Headers.Get('User-Agent');
affectedRows := FDeviceStore.ActivateSimpleDevice(Trim(DeviceKey), userAgent, normalizedPhone, LowerCase(Trim(DeviceType)));
affectedRows := FDeviceStore.ActivateSimpleDevice(Trim(DeviceKey), userAgent, normalizedPhone);
if affectedRows = 0 then
begin
......
......@@ -18,19 +18,6 @@ object FViewDeviceRegistration: TFViewDeviceRegistration
TextHint = '(303) 555-1234'
WidthPercent = 100.000000000000000000
end
object cmbDeviceType: TWebComboBox
Left = 240
Top = 110
Width = 177
Height = 25
ElementID = 'view.devicereg.devicetype'
ItemIndex = -1
Items.Strings = (
'iPhone'
'Android'
'Browser'
'Other')
end
object btnRegister: TWebButton
Left = 240
Top = 163
......
......@@ -33,7 +33,7 @@
<p class="text-muted small mb-3">
This browser has not been registered for emiMobile access.
Enter the phone number and select the device type your administrator registered for this device,
Enter the phone number your administrator registered for this device,
then click <strong>Send Code</strong>.
</p>
......@@ -46,11 +46,6 @@
autofocus>
</div>
<div class="mb-3">
<label class="form-label small text-muted" for="view.devicereg.devicetype">Device type</label>
<select id="view.devicereg.devicetype" class="form-select" aria-label="Device type"></select>
</div>
<div id="view.devicereg.verification" class="mb-3 d-none">
<label class="form-label small text-muted">Verification code</label>
<input id="view.devicereg.edtverificationcode"
......
......@@ -11,7 +11,6 @@ uses
type
TFViewDeviceRegistration = class(TWebForm)
edtPhoneNumber: TWebEdit;
cmbDeviceType: TWebComboBox;
btnRegister: TWebButton;
pnlVerification: TWebPanel;
edtVerificationCode: TWebEdit;
......@@ -26,7 +25,6 @@ type
procedure WebFormCreate(Sender: TObject);
private
FRegistrationProc: TSuccessProc;
FDeviceType: string;
procedure ShowNotification(const AMsg: string; AIsError: Boolean = True);
procedure HideNotification;
procedure SetBusy(ABusy: Boolean);
......@@ -92,7 +90,6 @@ end;
procedure TFViewDeviceRegistration.SetBusy(ABusy: Boolean);
begin
cmbDeviceType.Enabled := (not ABusy) and edtPhoneNumber.Enabled;
asm
var btn = document.getElementById('view.devicereg.btnregister');
if (btn) {
......@@ -121,7 +118,6 @@ var
begin
SetBusy(False);
edtPhoneNumber.Enabled := False;
cmbDeviceType.Enabled := False;
pnlVerification.ElementHandle.classList.remove('d-none');
edtVerificationCode.SetFocus;
ShowNotification('Verification code sent. Enter the six-digit code to continue.', False);
......@@ -141,17 +137,10 @@ begin
Exit;
end;
if cmbDeviceType.ItemIndex < 0 then
begin
ShowNotification('Please select the device type your administrator registered.');
Exit;
end;
FDeviceType := LowerCase(cmbDeviceType.Text);
SetBusy(True);
HideNotification;
AuthService.BeginRegistration(phoneNumber, FDeviceType, @OnCodeSent, @OnCodeError);
AuthService.BeginRegistration(phoneNumber, @OnCodeSent, @OnCodeError);
end;
procedure TFViewDeviceRegistration.btnVerifyCodeClick(Sender: TObject);
......@@ -189,7 +178,7 @@ begin
SetVerifyBusy(True);
HideNotification;
AuthService.VerifyRegistrationCode(phoneNumber, FDeviceType, verificationCode,
AuthService.VerifyRegistrationCode(phoneNumber, verificationCode,
@OnVerified, @OnVerifyError);
end;
......@@ -212,7 +201,7 @@ var
procedure OnCredential(ACredentialId, AAttestationObject, AClientDataJSON: string);
begin
AuthService.CompleteRegistration(
phoneNumber, FDeviceType, ACredentialId, AAttestationObject, AClientDataJSON, challengeToken,
phoneNumber, ACredentialId, AAttestationObject, AClientDataJSON, challengeToken,
@OnCompleteOK, @OnCompleteError
);
end;
......@@ -306,7 +295,7 @@ begin
end;
AuthService.CompleteRegistrationSimple(
phoneNumber, FDeviceType, deviceKey, challengeToken,
phoneNumber, deviceKey, challengeToken,
@OnCompleteOK, @OnCompleteError
);
end;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment