Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F13521689
verification-process-test.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
12 KB
Referenced Files
None
Subscribers
None
verification-process-test.cpp
View Options
/*
* This file is part of libkazv.
* SPDX-FileCopyrightText: 2021 Tusooa Zhu <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include
<libkazv-config.hpp>
#include
<catch2/catch.hpp>
#include
<iostream>
#include
<verification-process.hpp>
#include
<verification-tracker.hpp>
using
namespace
Kazv
;
// Taken from https://matrix.org/docs/spec/client_server/r0.6.1
static
auto
requestEvent
=
R
"
(
{
"content": {
"from_device": "AliceDevice2",
"methods": [
"m.sas.v1"
],
"timestamp": 1559598944869,
"transaction_id": "S0meUniqueAndOpaqueString"
},
"type": "m.key.verification.request"
}
)
"
_json
;
static
auto
requestEventUnsupportedMethod
=
R
"
(
{
"content": {
"from_device": "AliceDevice2",
"methods": [
"moe.kazv.mxc.fake-method"
],
"timestamp": 1559598944869,
"transaction_id": "S0meUniqueAndOpaqueString"
},
"type": "m.key.verification.request"
}
)
"
_json
;
static
auto
requestEventMultiMethods
=
R
"
(
{
"content": {
"from_device": "AliceDevice2",
"methods": [
"m.sas.v1",
"moe.kazv.mxc.fake-method"
],
"timestamp": 1559598944869,
"transaction_id": "S0meUniqueAndOpaqueString"
},
"type": "m.key.verification.request"
}
)
"
_json
;
static
auto
startEvent
=
R
"
(
{
"content": {
"from_device": "BobDevice1",
"method": "m.sas.v1",
"transaction_id": "S0meUniqueAndOpaqueString"
},
"type": "m.key.verification.start"
}
)
"
_json
;
static
auto
startEventUnsupportedMethod
=
R
"
(
{
"content": {
"from_device": "BobDevice1",
"method": "moe.kazv.mxc.fake-method",
"transaction_id": "S0meUniqueAndOpaqueString"
},
"type": "m.key.verification.start"
}
)
"
_json
;
static
auto
cancelEvent
=
R
"
(
{
"content": {
"code": "m.user",
"reason": "User rejected the key verification request",
"transaction_id": "S0meUniqueAndOpaqueString"
},
"type": "m.key.verification.cancel"
}
)
"
_json
;
static
auto
sasStartEvent
=
R
"
(
{
"content": {
"from_device": "BobDevice1",
"hashes": [
"sha256"
],
"key_agreement_protocols": [
"curve25519"
],
"message_authentication_codes": [
"hkdf-hmac-sha256"
],
"method": "m.sas.v1",
"short_authentication_string": [
"decimal",
"emoji"
],
"transaction_id": "S0meUniqueAndOpaqueString"
},
"type": "m.key.verification.start"
}
)
"
_json
;
static
auto
sasAcceptEvent
=
R
"
(
{
"content": {
"commitment": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg",
"hash": "sha256",
"key_agreement_protocol": "curve25519",
"message_authentication_code": "hkdf-hmac-sha256",
"method": "m.sas.v1",
"short_authentication_string": [
"decimal",
"emoji"
],
"transaction_id": "S0meUniqueAndOpaqueString"
},
"type": "m.key.verification.accept"
}
)
"
_json
;
static
auto
sasKeyEvent
=
R
"
(
{
"content": {
"key": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg",
"transaction_id": "S0meUniqueAndOpaqueString"
},
"type": "m.key.verification.key"
}
)
"
_json
;
static
auto
sasMacEvent
=
R
"
(
{
"content": {
"keys": "2Wptgo4CwmLo/Y8B8qinxApKaCkBG2fjTWB7AbP5Uy+aIbygsSdLOFzvdDjww8zUVKCmI02eP9xtyJxc/cLiBA",
"mac": {
"ed25519:ABCDEF": "fQpGIW1Snz+pwLZu6sTy2aHy/DYWWTspTJRPyNp0PKkymfIsNffysMl6ObMMFdIJhk6g6pwlIqZ54rxo8SLmAg"
},
"transaction_id": "S0meUniqueAndOpaqueString"
},
"type": "m.key.verification.mac"
}
)
"
_json
;
static
auto
unknownEvent
=
R
"
(
{
"content": {
"transaction_id": "xxx"
},
"type": "moe.kazv.mxc.key.verification.unknown"
}
)
"
_json
;
static
auto
malformedEvent
=
R
"
(
{
"type": "moe.kazv.mxc.key.verification.unknown"
}
)
"
_json
;
static
bool
displays
(
const
VerificationTrackerAction
&
action
)
{
return
std
::
holds_alternative
<
VerificationTrackerActions
::
DisplayCodes
>
(
action
)
||
std
::
holds_alternative
<
VerificationTrackerActions
::
ShowStatus
>
(
action
);
}
static
bool
displaysCode
(
const
VerificationTrackerAction
&
action
)
{
return
std
::
holds_alternative
<
VerificationTrackerActions
::
DisplayCodes
>
(
action
);
}
static
bool
displaysNothing
(
VerificationTrackerResult
res
)
{
return
std
::
all_of
(
res
.
begin
(),
res
.
end
(),
[](
const
auto
&
action
)
{
return
!
displays
(
action
);
});
}
static
bool
sendsEventOfType
(
VerificationTrackerResult
res
,
std
::
string
type
)
{
return
std
::
any_of
(
res
.
begin
(),
res
.
end
(),
[
=
](
const
auto
&
action
)
{
return
std
::
holds_alternative
<
VerificationTrackerActions
::
SendEvent
>
(
action
)
&&
std
::
get
<
VerificationTrackerActions
::
SendEvent
>
(
action
)
.
event
.
at
(
"type"
)
.
template
get
<
std
::
string
>
()
==
type
;
});
}
static
bool
sendsCancellation
(
VerificationTrackerResult
res
)
{
return
sendsEventOfType
(
res
,
"m.key.verification.cancel"
);
}
static
bool
sendsRequest
(
VerificationTrackerResult
res
)
{
return
sendsEventOfType
(
res
,
"m.key.verification.request"
);
}
static
bool
sendsStart
(
VerificationTrackerResult
res
)
{
return
sendsEventOfType
(
res
,
"m.key.verification.start"
);
}
static
bool
sendsAccept
(
VerificationTrackerResult
res
)
{
return
sendsEventOfType
(
res
,
"m.key.verification.accept"
);
}
static
bool
sendsKey
(
VerificationTrackerResult
res
)
{
return
sendsEventOfType
(
res
,
"m.key.verification.key"
);
}
static
bool
sendsMac
(
VerificationTrackerResult
res
)
{
return
sendsEventOfType
(
res
,
"m.key.verification.mac"
);
}
static
nlohmann
::
json
firstEventSent
(
VerificationTrackerResult
res
)
{
auto
it
=
std
::
find_if
(
res
.
begin
(),
res
.
end
(),
[](
const
auto
&
action
)
{
return
std
::
holds_alternative
<
VerificationTrackerActions
::
SendEvent
>
(
action
);
});
return
std
::
get
<
VerificationTrackerActions
::
SendEvent
>
(
*
it
).
event
;
}
static
bool
sendsNothing
(
VerificationTrackerResult
res
)
{
return
std
::
all_of
(
res
.
begin
(),
res
.
end
(),
[](
const
auto
&
action
)
{
return
!
std
::
holds_alternative
<
VerificationTrackerActions
::
SendEvent
>
(
action
);
});
}
// TEST_CASE("Construct sas verification process", "[client][verification-proc]")
// {
// auto proc1 = SASVerificationProcess();
// REQUIRE(!proc1.valid());
// auto proc2 = SASVerificationProcess(RandomTag{}, );
// }
TEST_CASE
(
"VerificationTracker is a value type"
,
"[client][verification-proc]"
)
{
auto
tracker
=
VerificationTracker
{};
auto
tracker2
=
tracker
;
(
void
)
tracker2
;
auto
tracker3
=
std
::
move
(
tracker
);
(
void
)
tracker3
;
}
TEST_CASE
(
"VerificationTracker processRandomSize"
,
"[client][verification-proc]"
)
{
auto
sasConstructRandomSize
=
SASVerificationProcess
::
constructRandomSize
();
REQUIRE
(
sasConstructRandomSize
!=
0
);
REQUIRE
(
VerificationTracker
::
processRandomSize
(
requestEvent
)
==
sasConstructRandomSize
);
REQUIRE
(
VerificationTracker
::
processRandomSize
(
requestEventUnsupportedMethod
)
==
0
);
REQUIRE
(
VerificationTracker
::
processRandomSize
(
requestEventMultiMethods
)
==
sasConstructRandomSize
);
REQUIRE
(
VerificationTracker
::
processRandomSize
(
startEvent
)
==
sasConstructRandomSize
);
REQUIRE
(
VerificationTracker
::
processRandomSize
(
sasStartEvent
)
==
sasConstructRandomSize
);
REQUIRE
(
VerificationTracker
::
processRandomSize
(
startEventUnsupportedMethod
)
==
0
);
REQUIRE
(
VerificationTracker
::
processRandomSize
(
cancelEvent
)
==
0
);
REQUIRE
(
VerificationTracker
::
processRandomSize
(
sasAcceptEvent
)
==
0
);
REQUIRE
(
VerificationTracker
::
processRandomSize
(
sasKeyEvent
)
==
0
);
REQUIRE
(
VerificationTracker
::
processRandomSize
(
sasMacEvent
)
==
0
);
REQUIRE
(
VerificationTracker
::
processRandomSize
(
unknownEvent
)
==
0
);
REQUIRE
(
VerificationTracker
::
processRandomSize
(
malformedEvent
)
==
0
);
}
TEST_CASE
(
"VerificationTracker process() error handling"
,
"[client][verification-proc]"
)
{
auto
reqRandomSize
=
VerificationTracker
::
processRandomSize
(
requestEvent
);
auto
random
=
genRandomData
(
reqRandomSize
);
auto
tracker
=
VerificationTracker
{};
auto
afterReasonablyShortTime
=
requestEvent
[
"content"
][
"timestamp"
].
template
get
<
Timestamp
>
()
+
1
;
WHEN
(
"processing a request way long ago"
)
{
auto
afterTenMins
=
requestEvent
[
"content"
][
"timestamp"
].
template
get
<
Timestamp
>
()
+
10
*
60
*
1000
+
1
;
auto
res
=
tracker
.
process
(
requestEvent
,
random
,
afterTenMins
);
THEN
(
"we should ignore and send cancellation"
)
{
REQUIRE
(
displaysNothing
(
res
));
REQUIRE
(
sendsCancellation
(
res
));
}
}
WHEN
(
"processing a request way in the future"
)
{
auto
beforeFiveMins
=
requestEvent
[
"content"
][
"timestamp"
].
template
get
<
Timestamp
>
()
-
5
*
60
*
1000
-
1
;
auto
res
=
tracker
.
process
(
requestEvent
,
random
,
beforeFiveMins
);
THEN
(
"we should ignore and send cancellation"
)
{
REQUIRE
(
displaysNothing
(
res
));
REQUIRE
(
sendsCancellation
(
res
));
}
}
WHEN
(
"processing a non-request, non-cancel event whose transaction id is never encountered"
)
{
auto
res
=
tracker
.
process
(
sasAcceptEvent
,
random
,
afterReasonablyShortTime
);
THEN
(
"we should ignore and send cancellation"
)
{
REQUIRE
(
displaysNothing
(
res
));
REQUIRE
(
sendsCancellation
(
res
));
}
}
WHEN
(
"processing a cancel event whose transaction id is never encountered"
)
{
auto
res
=
tracker
.
process
(
cancelEvent
,
random
,
afterReasonablyShortTime
);
THEN
(
"we should ignore only"
)
{
REQUIRE
(
displaysNothing
(
res
));
REQUIRE
(
sendsNothing
(
res
));
}
}
}
TEST_CASE
(
"VerificationTracker full process"
,
"[client][verification-proc]"
)
{
auto
alice
=
VerificationTracker
(
"@alice:example.org"
,
"AliceDevice1"
);
auto
bob
=
VerificationTracker
(
"@bob:example.org"
,
"BobDevice1"
);
auto
ts
=
1000
;
auto
requestRes
=
alice
.
requestVerification
(
"@bob:example.org"
,
{
"BobDevice1"
},
ts
);
THEN
(
"Alice should send a request event and notify"
)
{
REQUIRE
(
sendsRequest
(
requestRes
));
}
auto
requestEvent
=
firstEventSent
(
requestRes
);
auto
processRequestRes
=
bob
.
process
(
requestEvent
,
genRandomData
(
VerificationTracker
::
processRandomSize
(
requestEvent
)),
ts
);
THEN
(
"Bob should notify first and start sas"
)
{
REQUIRE
(
displays
(
processRequestRes
.
at
(
0
)));
REQUIRE
(
sendsStart
(
processRequestRes
));
}
auto
startEvent
=
firstEventSent
(
processRequestRes
);
auto
processStartRes
=
alice
.
process
(
startEvent
,
genRandomData
(
VerificationTracker
::
processRandomSize
(
startEvent
)),
ts
);
THEN
(
"Alice should notify first and accept sas"
)
{
REQUIRE
(
displays
(
processStartRes
.
at
(
0
)));
REQUIRE
(
sendsAccept
(
processStartRes
));
}
auto
acceptEvent
=
firstEventSent
(
processStartRes
);
auto
processAcceptRes
=
bob
.
process
(
acceptEvent
,
genRandomData
(
VerificationTracker
::
processRandomSize
(
acceptEvent
)),
ts
);
THEN
(
"Bob should notify and send key"
)
{
REQUIRE
(
!
displaysNothing
(
processAcceptRes
));
REQUIRE
(
sendsKey
(
processAcceptRes
));
}
auto
bobKeyEvent
=
firstEventSent
(
processAcceptRes
);
auto
aliceProcessKeyRes
=
alice
.
process
(
bobKeyEvent
,
genRandomData
(
VerificationTracker
::
processRandomSize
(
bobKeyEvent
)),
ts
);
THEN
(
"Alice should send key and display code"
)
{
REQUIRE
(
!
displaysNothing
(
aliceProcessKeyRes
));
REQUIRE
(
sendsKey
(
aliceProcessKeyRes
));
}
auto
aliceKeyEvent
=
firstEventSent
(
aliceProcessKeyRes
);
auto
bobProcessKeyRes
=
bob
.
process
(
aliceKeyEvent
,
genRandomData
(
VerificationTracker
::
processRandomSize
(
aliceKeyEvent
)),
ts
);
THEN
(
"Bob should display code first and send mac"
)
{
REQUIRE
(
displaysCode
(
bobProcessKeyRes
.
at
(
0
)));
REQUIRE
(
sendsMac
(
bobProcessKeyRes
));
}
auto
bobMacEvent
=
firstEventSent
(
bobProcessKeyRes
);
auto
aliceProcessMacRes
=
alice
.
process
(
bobMacEvent
,
genRandomData
(
VerificationTracker
::
processRandomSize
(
bobMacEvent
)),
ts
);
THEN
(
"Alice should send mac and show success"
)
{
REQUIRE
(
sendsMac
(
aliceProcessMacRes
));
REQUIRE
(
!
displaysNothing
(
aliceProcessMacRes
));
}
auto
aliceMacEvent
=
firstEventSent
(
aliceProcessMacRes
);
auto
bobProcessMacRes
=
bob
.
process
(
aliceMacEvent
,
genRandomData
(
VerificationTracker
::
processRandomSize
(
aliceMacEvent
)),
ts
);
THEN
(
"Bob should show success"
)
{
REQUIRE
(
sendsNothing
(
bobProcessMacRes
));
REQUIRE
(
!
displaysNothing
(
bobProcessMacRes
));
}
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sun, Dec 7, 8:29 PM (13 h, 27 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
700238
Default Alt Text
verification-process-test.cpp (12 KB)
Attached To
Mode
rL libkazv
Attached
Detach File
Event Timeline
Log In to Comment