Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F139976
crypto.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
21 KB
Referenced Files
None
Subscribers
None
crypto.cpp
View Options
/*
* This file is part of libkazv.
* SPDX-FileCopyrightText: 2020-2024 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include
<libkazv-config.hpp>
#include
<vector>
#include
<zug/transducer/filter.hpp>
#include
<vodozemac.h>
#include
<nlohmann/json.hpp>
#include
<debug.hpp>
#include
<event.hpp>
#include
<cursorutil.hpp>
#include
<types.hpp>
#include
"crypto-p.hpp"
#include
"session-p.hpp"
#include
"crypto-util-p.hpp"
#include
"crypto-util.hpp"
#include
"time-util.hpp"
namespace
Kazv
{
using
namespace
CryptoConstants
;
CryptoPrivate
::
CryptoPrivate
()
:
account
(
std
::
nullopt
)
,
valid
(
false
)
{
}
CryptoPrivate
::
CryptoPrivate
(
RandomTag
,
[[
maybe_unused
]]
RandomData
data
)
:
account
(
std
::
nullopt
)
,
valid
(
true
)
{
account
=
vodozemac
::
olm
::
new_account
();
}
CryptoPrivate
::~
CryptoPrivate
()
{
}
CryptoPrivate
::
CryptoPrivate
(
const
CryptoPrivate
&
that
)
:
account
(
std
::
nullopt
)
,
uploadedOneTimeKeysCount
(
that
.
uploadedOneTimeKeysCount
)
,
numUnpublishedKeys
(
that
.
numUnpublishedKeys
)
,
knownSessions
(
that
.
knownSessions
)
,
inboundGroupSessions
(
that
.
inboundGroupSessions
)
,
outboundGroupSessions
(
that
.
outboundGroupSessions
)
{
if
(
that
.
valid
)
{
valid
=
unpickle
(
that
.
pickle
());
}
}
std
::
string
CryptoPrivate
::
pickle
()
const
{
auto
pickleData
=
account
.
value
()
->
pickle
(
VODOZEMAC_PICKLE_KEY
);
return
static_cast
<
std
::
string
>
(
pickleData
);
}
bool
CryptoPrivate
::
unpickle
(
std
::
string
pickleData
)
{
account
=
checkVodozemacError
([
&
]()
{
return
vodozemac
::
olm
::
account_from_pickle
(
rust
::
Str
(
pickleData
),
VODOZEMAC_PICKLE_KEY
);
});
return
account
.
has_value
();
}
bool
CryptoPrivate
::
unpickleFromLibolm
(
std
::
string
pickleData
)
{
account
=
checkVodozemacError
([
&
]()
{
return
vodozemac
::
olm
::
account_from_libolm_pickle
(
rust
::
Str
(
pickleData
),
rust
::
Slice
<
const
unsigned
char
>
(
OLM_PICKLE_KEY
.
data
(),
OLM_PICKLE_KEY
.
size
())
);
});
return
account
.
has_value
();
}
MaybeString
CryptoPrivate
::
decryptOlm
(
nlohmann
::
json
content
)
{
auto
theirCurve25519IdentityKey
=
content
.
at
(
"sender_key"
).
get
<
std
::
string
>
();
auto
ourCurve25519IdentityKey
=
curve25519IdentityKey
();
if
(
!
content
.
at
(
"ciphertext"
).
contains
(
ourCurve25519IdentityKey
))
{
return
NotBut
(
"Message not intended for us"
);
}
auto
type
=
content
.
at
(
"ciphertext"
).
at
(
ourCurve25519IdentityKey
).
at
(
"type"
).
get
<
int
>
();
auto
body
=
content
.
at
(
"ciphertext"
).
at
(
ourCurve25519IdentityKey
).
at
(
"body"
).
get
<
std
::
string
>
();
auto
hasKnownSession
=
knownSessions
.
find
(
theirCurve25519IdentityKey
)
!=
knownSessions
.
end
();
if
(
type
==
0
)
{
// pre-key message
bool
shouldCreateNewSession
=
// there is no possible session
(
!
hasKnownSession
)
// the possible session does not match this message
||
(
!
knownSessions
.
at
(
theirCurve25519IdentityKey
).
matches
(
body
));
if
(
shouldCreateNewSession
)
{
auto
created
=
createInboundSession
(
theirCurve25519IdentityKey
,
body
);
if
(
!
created
)
{
// cannot create session, thus cannot decrypt
return
NotBut
(
"Cannot create session"
);
}
auto
&
session
=
knownSessions
.
at
(
theirCurve25519IdentityKey
);
return
session
.
m_d
->
takeFirstDecrypted
();
}
auto
&
session
=
knownSessions
.
at
(
theirCurve25519IdentityKey
);
return
session
.
decrypt
(
type
,
body
);
}
else
{
if
(
!
hasKnownSession
)
{
return
NotBut
(
"No available session"
);
}
auto
&
session
=
knownSessions
.
at
(
theirCurve25519IdentityKey
);
return
session
.
decrypt
(
type
,
body
);
}
}
MaybeString
CryptoPrivate
::
decryptMegOlm
(
nlohmann
::
json
eventJson
)
{
auto
content
=
eventJson
.
at
(
"content"
);
auto
sessionId
=
content
.
at
(
"session_id"
).
get
<
std
::
string
>
();
auto
roomId
=
eventJson
.
at
(
"room_id"
).
get
<
std
::
string
>
();
auto
k
=
KeyOfGroupSession
{
roomId
,
sessionId
};
if
(
inboundGroupSessions
.
find
(
k
)
==
inboundGroupSessions
.
end
())
{
return
NotBut
(
"We do not have the keys for this"
);
}
else
{
auto
msg
=
content
.
at
(
"ciphertext"
).
get
<
std
::
string
>
();
auto
eventId
=
eventJson
.
at
(
"event_id"
).
get
<
std
::
string
>
();
auto
originServerTs
=
eventJson
.
at
(
"origin_server_ts"
).
get
<
Timestamp
>
();
auto
&
session
=
inboundGroupSessions
.
at
(
k
);
return
session
.
decrypt
(
msg
,
eventId
,
originServerTs
);
}
}
bool
CryptoPrivate
::
createInboundSession
(
std
::
string
theirCurve25519IdentityKey
,
std
::
string
message
)
{
auto
s
=
Session
(
InboundSessionTag
{},
*
this
,
theirCurve25519IdentityKey
,
message
);
if
(
s
.
valid
())
{
knownSessions
.
insert_or_assign
(
theirCurve25519IdentityKey
,
std
::
move
(
s
));
return
true
;
}
return
false
;
}
bool
CryptoPrivate
::
reuseOrCreateOutboundGroupSession
(
RandomData
random
,
Timestamp
timeMs
,
std
::
string
roomId
,
std
::
optional
<
MegOlmSessionRotateDesc
>
desc
)
{
bool
valid
=
true
;
if
(
!
desc
.
has_value
())
{
// force rotate
valid
=
false
;
}
else
{
auto
it
=
outboundGroupSessions
.
find
(
roomId
);
if
(
it
==
outboundGroupSessions
.
end
())
{
valid
=
false
;
}
else
{
auto
&
session
=
it
->
second
;
if
(
timeMs
-
session
.
creationTimeMs
()
>=
desc
.
value
().
ms
)
{
valid
=
false
;
}
else
if
(
session
.
messageIndex
()
>=
desc
.
value
().
messages
)
{
valid
=
false
;
}
}
}
if
(
!
valid
)
{
outboundGroupSessions
.
insert_or_assign
(
roomId
,
OutboundGroupSession
(
RandomTag
{},
random
,
timeMs
));
auto
&
session
=
outboundGroupSessions
.
at
(
roomId
);
auto
sessionId
=
session
.
sessionId
();
auto
sessionKey
=
session
.
sessionKey
();
auto
k
=
KeyOfGroupSession
{
roomId
,
sessionId
};
if
(
!
createInboundGroupSession
(
k
,
sessionKey
,
ed25519IdentityKey
()))
{
kzo
.
client
.
warn
()
<<
"Create inbound group session from outbound group session failed. We may not be able to read our own messages."
<<
std
::
endl
;
}
}
return
valid
;
}
std
::
size_t
Crypto
::
constructRandomSize
()
{
return
0
;
}
Crypto
::
Crypto
()
:
m_d
(
new
CryptoPrivate
{})
{
}
Crypto
::
Crypto
(
RandomTag
,
RandomData
data
)
:
m_d
(
new
CryptoPrivate
(
RandomTag
{},
std
::
move
(
data
)))
{
}
Crypto
::~
Crypto
()
=
default
;
Crypto
::
Crypto
(
const
Crypto
&
that
)
:
m_d
(
new
CryptoPrivate
(
*
that
.
m_d
))
{
}
Crypto
::
Crypto
(
Crypto
&&
that
)
:
m_d
(
std
::
move
(
that
.
m_d
))
{
}
Crypto
&
Crypto
::
operator
=
(
const
Crypto
&
that
)
{
m_d
.
reset
(
new
CryptoPrivate
(
*
that
.
m_d
));
return
*
this
;
}
Crypto
&
Crypto
::
operator
=
(
Crypto
&&
that
)
{
m_d
=
std
::
move
(
that
.
m_d
);
return
*
this
;
}
bool
Crypto
::
operator
==
(
const
Crypto
&
that
)
const
{
return
this
->
m_d
==
that
.
m_d
;
}
bool
Crypto
::
valid
()
const
{
return
m_d
->
valid
;
}
std
::
string
CryptoPrivate
::
ed25519IdentityKey
()
const
{
auto
key
=
account
.
value
()
->
ed25519_key
()
->
to_base64
();
return
static_cast
<
std
::
string
>
(
key
);
}
std
::
string
CryptoPrivate
::
curve25519IdentityKey
()
const
{
auto
key
=
account
.
value
()
->
curve25519_key
()
->
to_base64
();
return
static_cast
<
std
::
string
>
(
key
);
}
std
::
string
Crypto
::
ed25519IdentityKey
()
const
{
return
m_d
->
ed25519IdentityKey
();
}
std
::
string
Crypto
::
curve25519IdentityKey
()
const
{
return
m_d
->
curve25519IdentityKey
();
}
std
::
string
Crypto
::
sign
(
nlohmann
::
json
j
)
{
j
.
erase
(
"signatures"
);
j
.
erase
(
"unsigned"
);
auto
str
=
j
.
dump
();
auto
signature
=
checkVodozemacError
([
&
]()
{
return
m_d
->
account
.
value
()
->
sign
(
str
);
});
if
(
!
signature
.
has_value
())
{
return
""
;
}
return
static_cast
<
std
::
string
>
(
signature
.
value
()
->
to_base64
());
}
void
Crypto
::
setUploadedOneTimeKeysCount
(
immer
::
map
<
std
::
string
/* algorithm */
,
int
>
uploadedOneTimeKeysCount
)
{
m_d
->
uploadedOneTimeKeysCount
=
uploadedOneTimeKeysCount
;
}
std
::
size_t
Crypto
::
maxNumberOfOneTimeKeys
()
const
{
return
m_d
->
account
.
value
()
->
max_number_of_one_time_keys
();
}
std
::
size_t
Crypto
::
genOneTimeKeysRandomSize
(
int
num
)
{
return
0
;
}
void
Crypto
::
genOneTimeKeysWithRandom
(
RandomData
random
,
int
num
)
{
assert
(
random
.
size
()
>=
genOneTimeKeysRandomSize
(
num
));
m_d
->
account
.
value
()
->
generate_one_time_keys
(
num
);
m_d
->
numUnpublishedKeys
+=
num
;
}
nlohmann
::
json
Crypto
::
unpublishedOneTimeKeys
()
const
{
auto
keys
=
m_d
->
account
.
value
()
->
one_time_keys
();
auto
ret
=
nlohmann
::
json
{
{
curve25519
,
nlohmann
::
json
::
object
()},
};
for
(
const
auto
&
k
:
keys
)
{
auto
keyId
=
static_cast
<
std
::
string
>
(
k
.
key_id
);
auto
key
=
static_cast
<
std
::
string
>
(
k
.
key
->
to_base64
());
ret
[
curve25519
][
keyId
]
=
key
;
}
return
ret
;
}
void
Crypto
::
markOneTimeKeysAsPublished
()
{
m_d
->
account
.
value
()
->
mark_keys_as_published
();
m_d
->
numUnpublishedKeys
=
0
;
}
int
Crypto
::
numUnpublishedOneTimeKeys
()
const
{
return
m_d
->
numUnpublishedKeys
;
}
int
Crypto
::
uploadedOneTimeKeysCount
(
std
::
string
algorithm
)
const
{
return
m_d
->
uploadedOneTimeKeysCount
[
algorithm
];
}
MaybeString
Crypto
::
decrypt
(
nlohmann
::
json
eventJson
)
{
auto
content
=
eventJson
.
at
(
"content"
);
auto
algo
=
content
.
contains
(
"algorithm"
)
?
content
.
at
(
"algorithm"
).
template
get
<
std
::
string
>
()
:
std
::
string
();
if
(
algo
==
olmAlgo
)
{
return
m_d
->
decryptOlm
(
std
::
move
(
content
));
}
else
if
(
algo
==
megOlmAlgo
)
{
return
m_d
->
decryptMegOlm
(
eventJson
);
}
return
NotBut
(
"Algorithm "
+
algo
+
" not supported"
);
}
bool
Crypto
::
createInboundGroupSession
(
KeyOfGroupSession
k
,
std
::
string
sessionKey
,
std
::
string
ed25519Key
)
{
return
m_d
->
createInboundGroupSession
(
std
::
move
(
k
),
std
::
move
(
sessionKey
),
std
::
move
(
ed25519Key
));
}
bool
Crypto
::
hasInboundGroupSession
(
KeyOfGroupSession
k
)
const
{
return
m_d
->
inboundGroupSessions
.
find
(
k
)
!=
m_d
->
inboundGroupSessions
.
end
();
}
bool
CryptoPrivate
::
createInboundGroupSession
(
KeyOfGroupSession
k
,
std
::
string
sessionKey
,
std
::
string
ed25519Key
)
{
auto
session
=
InboundGroupSession
(
sessionKey
,
ed25519Key
);
if
(
!
session
.
valid
())
{
kzo
.
crypto
.
warn
()
<<
"Invalid session key for: "
<<
k
.
roomId
<<
", "
<<
k
.
sessionId
<<
std
::
endl
;
return
false
;
}
auto
currentSessionIt
=
inboundGroupSessions
.
find
(
k
);
if
(
currentSessionIt
==
inboundGroupSessions
.
end
())
{
// the session is new, insert it
inboundGroupSessions
.
insert
({
k
,
std
::
move
(
session
)});
return
true
;
}
// the session already exists, do some check
auto
&
currentSession
=
currentSessionIt
->
second
;
if
(
currentSession
.
ed25519Key
()
!=
ed25519Key
)
{
return
false
;
}
return
currentSession
.
merge
(
session
);
}
bool
Crypto
::
verify
(
nlohmann
::
json
object
,
std
::
string
userId
,
std
::
string
deviceId
,
std
::
string
ed25519Key
)
{
if
(
!
object
.
contains
(
"signatures"
))
{
return
false
;
}
std
::
string
signature
;
try
{
signature
=
object
.
at
(
"signatures"
).
at
(
userId
).
at
(
ed25519
+
":"
+
deviceId
);
}
catch
(
const
std
::
exception
&
)
{
return
false
;
}
object
.
erase
(
"signatures"
);
object
.
erase
(
"unsigned"
);
auto
message
=
object
.
dump
();
auto
res
=
checkVodozemacError
([
&
]()
{
auto
key
=
vodozemac
::
types
::
ed25519_key_from_base64
(
ed25519Key
);
auto
sig
=
vodozemac
::
types
::
ed25519_signature_from_base64
(
signature
);
key
->
verify
(
message
,
*
sig
);
// It throws if the signature cannot be verified
return
true
;
});
return
res
.
has_value
()
&&
res
.
value
();
}
MaybeString
Crypto
::
getInboundGroupSessionEd25519KeyFromEvent
(
const
nlohmann
::
json
&
eventJson
)
const
{
auto
content
=
eventJson
.
at
(
"content"
);
auto
sessionId
=
content
.
at
(
"session_id"
).
get
<
std
::
string
>
();
auto
roomId
=
eventJson
.
at
(
"room_id"
).
get
<
std
::
string
>
();
auto
k
=
KeyOfGroupSession
{
roomId
,
sessionId
};
if
(
m_d
->
inboundGroupSessions
.
find
(
k
)
==
m_d
->
inboundGroupSessions
.
end
())
{
return
NotBut
(
"We do not have the keys for this"
);
}
else
{
auto
&
session
=
m_d
->
inboundGroupSessions
.
at
(
k
);
return
session
.
ed25519Key
();
}
}
std
::
size_t
Crypto
::
encryptOlmRandomSize
(
std
::
string
/* theirCurve25519IdentityKey */
)
const
{
// HACK: To prevent a possible race condition where we call
// encryptedOlmRandomSize() -> randomGenerator.generateRange() ~> [encryptOlm()]
//
// Here, encryptOlm() must be called in the reducer,
// as it changes the status of
// Crypto (so we should not risk any infomation lose in Crypto).
// Also, for the reducer to be pure, we may not call generateRange() in the reducer,
// as *that* is not a pure function. This means it can only be called in an effect,
// or .then() continuation. This means, the sequence from encryptedOlmRandomSize()
// to encryptOlm() can never be atomic. That is, there may be other encryptOlm()
// calls within, and that may increase the random data needed, and as a result,
// we will not have enough random data.
//
// According to the olm headers:
// https://gitlab.matrix.org/matrix-org/olm/-/blob/master/include/olm/ratchet.hh
// The maximum random size needed to encrypt is 32. We use this to ensure we
// will always have enough random data fot the encryption.
return
encryptOlmMaxRandomSize
();
}
std
::
size_t
Crypto
::
encryptOlmMaxRandomSize
()
{
return
0
;
}
nlohmann
::
json
Crypto
::
encryptOlmWithRandom
(
RandomData
random
,
nlohmann
::
json
eventJson
,
std
::
string
theirCurve25519IdentityKey
)
{
assert
(
random
.
size
()
>=
encryptOlmRandomSize
(
theirCurve25519IdentityKey
));
try
{
auto
&
session
=
m_d
->
knownSessions
.
at
(
theirCurve25519IdentityKey
);
auto
[
type
,
body
]
=
session
.
encryptWithRandom
(
random
,
eventJson
.
dump
());
return
nlohmann
::
json
{
{
theirCurve25519IdentityKey
,
{
{
"type"
,
type
},
{
"body"
,
body
}
}
}
};
}
catch
(
const
std
::
exception
&
)
{
return
nlohmann
::
json
::
object
();
}
}
nlohmann
::
json
Crypto
::
encryptMegOlm
(
nlohmann
::
json
eventJson
)
{
auto
roomId
=
eventJson
.
at
(
"room_id"
).
get
<
std
::
string
>
();
auto
content
=
eventJson
.
at
(
"content"
);
auto
type
=
eventJson
.
at
(
"type"
).
get
<
std
::
string
>
();
auto
jsonToEncrypt
=
nlohmann
::
json
::
object
();
jsonToEncrypt
[
"room_id"
]
=
roomId
;
jsonToEncrypt
[
"content"
]
=
std
::
move
(
content
);
jsonToEncrypt
[
"type"
]
=
type
;
auto
textToEncrypt
=
std
::
move
(
jsonToEncrypt
).
dump
();
auto
&
session
=
m_d
->
outboundGroupSessions
.
at
(
roomId
);
auto
ciphertext
=
session
.
encrypt
(
std
::
move
(
textToEncrypt
));
return
json
{
{
"algorithm"
,
CryptoConstants
::
megOlmAlgo
},
// NOTE: we might stop sending sender_key in the future
// as per the Matrix spec
{
"sender_key"
,
curve25519IdentityKey
()},
{
"ciphertext"
,
ciphertext
},
{
"session_id"
,
session
.
sessionId
()},
};
}
std
::
size_t
Crypto
::
rotateMegOlmSessionRandomSize
()
{
return
OutboundGroupSession
::
constructRandomSize
();
}
std
::
string
Crypto
::
rotateMegOlmSessionWithRandom
(
RandomData
random
,
Timestamp
timeMs
,
std
::
string
roomId
)
{
m_d
->
reuseOrCreateOutboundGroupSession
(
random
,
timeMs
,
roomId
,
std
::
nullopt
);
return
outboundGroupSessionCurrentKey
(
roomId
);
}
std
::
optional
<
std
::
string
>
Crypto
::
rotateMegOlmSessionWithRandomIfNeeded
(
RandomData
random
,
Timestamp
timeMs
,
std
::
string
roomId
,
MegOlmSessionRotateDesc
desc
)
{
auto
oldSessionValid
=
m_d
->
reuseOrCreateOutboundGroupSession
(
random
,
timeMs
,
roomId
,
std
::
move
(
desc
));
return
oldSessionValid
?
std
::
nullopt
:
std
::
optional
(
outboundGroupSessionCurrentKey
(
roomId
));
}
std
::
string
Crypto
::
outboundGroupSessionInitialKey
(
std
::
string
roomId
)
{
auto
&
session
=
m_d
->
outboundGroupSessions
.
at
(
roomId
);
return
session
.
initialSessionKey
();
}
std
::
string
Crypto
::
outboundGroupSessionCurrentKey
(
std
::
string
roomId
)
{
auto
&
session
=
m_d
->
outboundGroupSessions
.
at
(
roomId
);
return
session
.
sessionKey
();
}
auto
Crypto
::
devicesMissingOutboundSessionKey
(
immer
::
map
<
std
::
string
,
immer
::
map
<
std
::
string
/* deviceId */
,
std
::
string
/* curve25519IdentityKey */
>>
keyMap
)
const
->
UserIdToDeviceIdMap
{
auto
ret
=
UserIdToDeviceIdMap
{};
for
(
auto
[
userId
,
devices
]
:
keyMap
)
{
auto
unknownDevices
=
intoImmer
(
immer
::
flex_vector
<
std
::
string
>
{},
zug
::
filter
([
=
](
auto
kv
)
{
auto
[
deviceId
,
theirCurve25519IdentityKey
]
=
kv
;
return
m_d
->
knownSessions
.
find
(
theirCurve25519IdentityKey
)
==
m_d
->
knownSessions
.
end
();
})
|
zug
::
map
([
=
](
auto
kv
)
{
auto
[
deviceId
,
key
]
=
kv
;
return
deviceId
;
}),
devices
);
if
(
!
unknownDevices
.
empty
())
{
ret
=
std
::
move
(
ret
).
set
(
userId
,
std
::
move
(
unknownDevices
));
}
}
return
ret
;
}
std
::
size_t
Crypto
::
createOutboundSessionRandomSize
()
{
return
Session
::
constructOutboundRandomSize
();
}
void
Crypto
::
createOutboundSessionWithRandom
(
RandomData
random
,
std
::
string
theirIdentityKey
,
std
::
string
theirOneTimeKey
)
{
assert
(
random
.
size
()
>=
createOutboundSessionRandomSize
());
auto
session
=
Session
(
OutboundSessionTag
{},
RandomTag
{},
random
,
*
m_d
,
theirIdentityKey
,
theirOneTimeKey
);
if
(
session
.
valid
())
{
m_d
->
knownSessions
.
insert_or_assign
(
theirIdentityKey
,
std
::
move
(
session
));
}
}
nlohmann
::
json
Crypto
::
toJson
()
const
{
std
::
string
pickledData
=
m_d
->
valid
?
m_d
->
pickle
()
:
std
::
string
();
auto
j
=
nlohmann
::
json
::
object
({
{
"valid"
,
m_d
->
valid
},
{
"version"
,
1
},
{
"account"
,
std
::
move
(
pickledData
)},
{
"uploadedOneTimeKeysCount"
,
m_d
->
uploadedOneTimeKeysCount
},
{
"numUnpublishedKeys"
,
m_d
->
numUnpublishedKeys
},
{
"knownSessions"
,
nlohmann
::
json
(
m_d
->
knownSessions
)},
{
"inboundGroupSessions"
,
nlohmann
::
json
(
m_d
->
inboundGroupSessions
)},
{
"outboundGroupSessions"
,
nlohmann
::
json
(
m_d
->
outboundGroupSessions
)},
});
return
j
;
}
void
Crypto
::
loadJson
(
const
nlohmann
::
json
&
j
)
{
m_d
->
valid
=
j
.
contains
(
"valid"
)
?
j
[
"valid"
].
template
get
<
bool
>
()
:
true
;
const
auto
&
pickledData
=
j
.
at
(
"account"
).
template
get
<
std
::
string
>
();
if
(
m_d
->
valid
)
{
if
(
j
.
contains
(
"version"
)
&&
j
[
"version"
]
==
1
)
{
m_d
->
valid
=
m_d
->
unpickle
(
pickledData
);
}
else
{
m_d
->
valid
=
m_d
->
unpickleFromLibolm
(
pickledData
);
}
}
m_d
->
uploadedOneTimeKeysCount
=
j
.
at
(
"uploadedOneTimeKeysCount"
);
m_d
->
numUnpublishedKeys
=
j
.
at
(
"numUnpublishedKeys"
);
m_d
->
knownSessions
=
j
.
at
(
"knownSessions"
).
template
get
<
decltype
(
m_d
->
knownSessions
)
>
();
m_d
->
inboundGroupSessions
=
j
.
at
(
"inboundGroupSessions"
).
template
get
<
decltype
(
m_d
->
inboundGroupSessions
)
>
();
m_d
->
outboundGroupSessions
=
j
.
at
(
"outboundGroupSessions"
).
template
get
<
decltype
(
m_d
->
outboundGroupSessions
)
>
();
}
}
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Sun, Jan 19, 9:26 AM (2 h, 13 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
55063
Default Alt Text
crypto.cpp (21 KB)
Attached To
Mode
rL libkazv
Attached
Detach File
Event Timeline
Log In to Comment