matrix_sdk_qrcode/types.rs
1// Copyright 2021 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::io::{Cursor, Read};
16
17use byteorder::{BigEndian, ReadBytesExt};
18use qrcode::QrCode;
19use ruma::serde::Base64;
20use vodozemac::Ed25519PublicKey;
21
22use crate::{
23 error::{DecodingError, EncodingError},
24 utils::{HEADER, MAX_MODE, MIN_SECRET_LEN, VERSION, to_bytes, to_qr_code},
25};
26
27/// An enum representing the different modes for a QR verification code.
28#[derive(Clone, Debug, PartialEq, Eq)]
29pub enum QrVerificationData {
30 /// The QR verification is verifying another user.
31 ///
32 /// It relies on both devices already trusting or owning the master
33 /// cross-signing key for the corresponding user.
34 ///
35 /// In this case, the QR code data includes:
36 ///
37 /// - The master cross-signing key of the displaying device's user.
38 /// - What the displaying device believes is the master cross-signing key of
39 /// the scanning device's user.
40 ///
41 /// After a successful verification, each device will trust the
42 /// cross-signing key of the other user, and will upload a cross-signature
43 /// of that key.
44 Verification(VerificationData),
45
46 /// The QR verification is self-verifying and the device displaying the QR
47 /// code trusts or owns the master cross-signing key.
48 ///
49 /// This normally happens when the displaying device is an existing device,
50 /// and the scanning device is new.
51 ///
52 /// In this case, the QR code data includes:
53 ///
54 /// - The master cross-signing key (which is trusted by the displaying
55 /// device).
56 /// - What the displaying device believes is the device key of the scanning
57 /// device.
58 ///
59 /// After a successful verification, the scanning device will be able to
60 /// trust the master key, and the displaying device will be able to trust
61 /// the scanning device's device key.
62 ///
63 /// Since the displaying device should be cross-signed already, this means
64 /// that the scanning device will now trust the displaying device.
65 ///
66 /// The displaying device will then upload a cross-signature of the scanning
67 /// device (assuming it has the private key), and will send the secret keys
68 /// to the scanning device.
69 SelfVerification(SelfVerificationData),
70
71 /// The QR verification is self-verifying in which the current device does
72 /// not yet trust the master key.
73 ///
74 /// This normally happens when the displaying device is new, and the
75 /// scanning device is an existing device.
76 ///
77 /// In this case, the QR code data includes:
78 ///
79 /// - The displaying device's device key.
80 /// - What the displaying device believes is the master cross-signing key.
81 ///
82 /// If the verification is successful, the scanning device will be able to
83 /// trust the displaying device's device key, and the displaying device will
84 /// be able to trust the master key.
85 ///
86 /// Since the scanning device should be cross-signed already, this means
87 /// that the displaying device will now trust the scanning device.
88 ///
89 /// The scanning device will then upload a cross-signature of the displaying
90 /// device (assuming it has the private key), and will send the secret keys
91 /// to the displaying device.
92 SelfVerificationNoMasterKey(SelfVerificationNoMasterKey),
93}
94
95impl TryFrom<&[u8]> for QrVerificationData {
96 type Error = DecodingError;
97
98 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
99 Self::from_bytes(value)
100 }
101}
102
103impl TryFrom<Vec<u8>> for QrVerificationData {
104 type Error = DecodingError;
105
106 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
107 Self::from_bytes(value)
108 }
109}
110
111impl QrVerificationData {
112 /// Parse the decoded payload of a QR code in byte slice form as a
113 /// `QrVerificationData`
114 ///
115 /// This method is useful if you would like to do your own custom QR code
116 /// decoding.
117 ///
118 /// # Arguments
119 ///
120 /// - `bytes` - The raw bytes of a decoded QR code.
121 ///
122 /// # Examples
123 ///
124 /// ```
125 /// # use matrix_sdk_qrcode::{QrVerificationData, DecodingError};
126 /// # fn main() -> Result<(), DecodingError> {
127 /// let data = b"MATRIX\
128 /// \x02\x02\x00\x07\
129 /// FLOW_ID\
130 /// kS /\x92i\x1e6\xcd'g\xf9#\x11\xd8\x8a\xa2\xf61\x05\x1b6\xef\xfc\xa4%\x80\x1a\x0c\xd2\xe8\x04\
131 /// \xbdR|\xf8n\x07\xa4\x1f\xb4\xcc3\x0eBT\xe7[~\xfd\x87\xd06B\xdfoVv%\x9b\x86\xae\xbcM\
132 /// SHARED_SECRET";
133 ///
134 /// let result = QrVerificationData::from_bytes(data)?;
135 /// # Ok(())
136 /// # }
137 /// ```
138 pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, DecodingError> {
139 Self::decode_bytes(bytes)
140 }
141
142 /// Encode the `QrVerificationData` into a `QrCode`.
143 ///
144 /// This method turns the `QrVerificationData` into a QR code that can be
145 /// rendered and presented to be scanned.
146 ///
147 /// The encoding can fail if the data doesn't fit into a QR code or if the
148 /// identity keys that should be encoded into the QR code are not valid
149 /// base64.
150 ///
151 /// # Examples
152 ///
153 /// ```
154 /// # use matrix_sdk_qrcode::{QrVerificationData, DecodingError};
155 /// # fn main() -> Result<(), DecodingError> {
156 /// let data = b"MATRIX\
157 /// \x02\x02\x00\x07\
158 /// FLOW_ID\
159 /// kS /\x92i\x1e6\xcd'g\xf9#\x11\xd8\x8a\xa2\xf61\x05\x1b6\xef\xfc\xa4%\x80\x1a\x0c\xd2\xe8\x04\
160 /// \xbdR|\xf8n\x07\xa4\x1f\xb4\xcc3\x0eBT\xe7[~\xfd\x87\xd06B\xdfoVv%\x9b\x86\xae\xbcM\
161 /// SHARED_SECRET";
162 ///
163 /// let result = QrVerificationData::from_bytes(data)?;
164 /// let encoded = result.to_qr_code().unwrap();
165 /// # Ok(())
166 /// # }
167 /// ```
168 pub fn to_qr_code(&self) -> Result<QrCode, EncodingError> {
169 match self {
170 QrVerificationData::Verification(v) => v.to_qr_code(),
171 QrVerificationData::SelfVerification(v) => v.to_qr_code(),
172 QrVerificationData::SelfVerificationNoMasterKey(v) => v.to_qr_code(),
173 }
174 }
175
176 /// Encode the `QrVerificationData` into a vector of bytes that can be
177 /// encoded as a QR code.
178 ///
179 /// The encoding can fail if the identity keys that should be encoded are
180 /// not valid base64.
181 ///
182 /// # Examples
183 ///
184 /// ```
185 /// # use matrix_sdk_qrcode::{QrVerificationData, DecodingError};
186 /// # fn main() -> Result<(), DecodingError> {
187 /// let data = b"MATRIX\
188 /// \x02\x02\x00\x07\
189 /// FLOW_ID\
190 /// kS /\x92i\x1e6\xcd'g\xf9#\x11\xd8\x8a\xa2\xf61\x05\x1b6\xef\xfc\xa4%\x80\x1a\x0c\xd2\xe8\x04\
191 /// \xbdR|\xf8n\x07\xa4\x1f\xb4\xcc3\x0eBT\xe7[~\xfd\x87\xd06B\xdfoVv%\x9b\x86\xae\xbcM\
192 /// SHARED_SECRET";
193 ///
194 /// let result = QrVerificationData::from_bytes(data)?;
195 /// let encoded = result.to_bytes().unwrap();
196 ///
197 /// assert_eq!(data.as_ref(), encoded.as_slice());
198 /// # Ok(())
199 /// # }
200 /// ```
201 pub fn to_bytes(&self) -> Result<Vec<u8>, EncodingError> {
202 match self {
203 QrVerificationData::Verification(v) => v.to_bytes(),
204 QrVerificationData::SelfVerification(v) => v.to_bytes(),
205 QrVerificationData::SelfVerificationNoMasterKey(v) => v.to_bytes(),
206 }
207 }
208
209 /// Decode the byte slice containing the decoded QR code data.
210 ///
211 /// The format is defined in the [spec].
212 ///
213 /// The byte slice consists of the following parts:
214 ///
215 /// - the ASCII string MATRIX
216 /// - one byte indicating the QR code version (must be 0x02)
217 /// - one byte indicating the QR code verification mode. one of the
218 /// following values:
219 /// - 0x00 verifying another user with cross-signing
220 /// - 0x01 self-verifying in which the current device does trust the
221 /// master key
222 /// - 0x02 self-verifying in which the current device does not yet trust
223 /// the master key
224 /// - the event ID or transaction_id of the associated verification request
225 /// event, encoded as:
226 /// - two bytes in network byte order (big-endian) indicating the length
227 /// in bytes of the ID as a UTF-8 string
228 /// - the ID as a UTF-8 string
229 /// - the first key, as 32 bytes
230 /// - the second key, as 32 bytes
231 /// - a random shared secret, as a byte string. as we do not share the
232 /// length of the secret, and it is not a fixed size, clients will just
233 /// use the remainder of binary string as the shared secret.
234 ///
235 /// [spec]: https://spec.matrix.org/unstable/client-server-api/#qr-code-format
236 fn decode_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, DecodingError> {
237 let mut decoded = Cursor::new(bytes);
238
239 let mut header = [0u8; 6];
240 let mut first_key = [0u8; 32];
241 let mut second_key = [0u8; 32];
242
243 decoded.read_exact(&mut header)?;
244 let version = decoded.read_u8()?;
245 let mode = decoded.read_u8()?;
246
247 if header != HEADER {
248 return Err(DecodingError::Header);
249 } else if version != VERSION {
250 return Err(DecodingError::Version(version));
251 } else if mode > MAX_MODE {
252 return Err(DecodingError::Mode(mode));
253 }
254
255 let flow_id_len = decoded.read_u16::<BigEndian>()?;
256 let mut flow_id = vec![0; flow_id_len.into()];
257
258 decoded.read_exact(&mut flow_id)?;
259 decoded.read_exact(&mut first_key)?;
260 decoded.read_exact(&mut second_key)?;
261
262 let mut shared_secret = Vec::new();
263
264 decoded.read_to_end(&mut shared_secret)?;
265
266 if shared_secret.len() < MIN_SECRET_LEN {
267 return Err(DecodingError::SharedSecret(shared_secret.len()));
268 }
269
270 let first_key = Ed25519PublicKey::from_slice(&first_key)?;
271 let second_key = Ed25519PublicKey::from_slice(&second_key)?;
272
273 QrVerificationData::new(mode, flow_id, first_key, second_key, shared_secret)
274 }
275
276 fn new(
277 mode: u8,
278 flow_id: Vec<u8>,
279 first_key: Ed25519PublicKey,
280 second_key: Ed25519PublicKey,
281 shared_secret: Vec<u8>,
282 ) -> Result<Self, DecodingError> {
283 let flow_id = String::from_utf8(flow_id)?;
284 let shared_secret = Base64::new(shared_secret);
285
286 match mode {
287 VerificationData::QR_MODE => {
288 Ok(VerificationData::new(flow_id, first_key, second_key, shared_secret).into())
289 }
290 SelfVerificationData::QR_MODE => {
291 Ok(SelfVerificationData::new(flow_id, first_key, second_key, shared_secret).into())
292 }
293 SelfVerificationNoMasterKey::QR_MODE => {
294 Ok(SelfVerificationNoMasterKey::new(flow_id, first_key, second_key, shared_secret)
295 .into())
296 }
297 m => Err(DecodingError::Mode(m)),
298 }
299 }
300
301 /// Get the flow id for this `QrVerificationData`.
302 ///
303 /// This represents the ID as a string even if it is a `EventId`.
304 pub fn flow_id(&self) -> &str {
305 match self {
306 QrVerificationData::Verification(v) => v.flow_id.as_str(),
307 QrVerificationData::SelfVerification(v) => &v.transaction_id,
308 QrVerificationData::SelfVerificationNoMasterKey(v) => &v.transaction_id,
309 }
310 }
311
312 /// Get the first key of this `QrVerificationData`.
313 pub fn first_key(&self) -> Ed25519PublicKey {
314 match self {
315 QrVerificationData::Verification(v) => v.first_master_key,
316 QrVerificationData::SelfVerification(v) => v.master_key,
317 QrVerificationData::SelfVerificationNoMasterKey(v) => v.device_key,
318 }
319 }
320
321 /// Get the second key of this `QrVerificationData`.
322 pub fn second_key(&self) -> Ed25519PublicKey {
323 match self {
324 QrVerificationData::Verification(v) => v.second_master_key,
325 QrVerificationData::SelfVerification(v) => v.device_key,
326 QrVerificationData::SelfVerificationNoMasterKey(v) => v.master_key,
327 }
328 }
329
330 /// Get the secret of this `QrVerificationData`.
331 pub fn secret(&self) -> &Base64 {
332 match self {
333 QrVerificationData::Verification(v) => &v.shared_secret,
334 QrVerificationData::SelfVerification(v) => &v.shared_secret,
335 QrVerificationData::SelfVerificationNoMasterKey(v) => &v.shared_secret,
336 }
337 }
338}
339
340/// The non-encoded data for the first mode of QR code verification.
341///
342/// This mode is used for verification between two users using their master
343/// cross signing keys.
344#[derive(Clone, Debug, PartialEq, Eq)]
345pub struct VerificationData {
346 flow_id: String,
347 first_master_key: Ed25519PublicKey,
348 second_master_key: Ed25519PublicKey,
349 shared_secret: Base64,
350}
351
352impl VerificationData {
353 const QR_MODE: u8 = 0x00;
354
355 /// Create a new `VerificationData` struct that can be encoded as a QR code.
356 ///
357 /// # Arguments
358 ///
359 /// - `flow_id` - The event ID or transaction ID of the
360 /// `m.key.verification.request` event that initiated the verification
361 /// flow this QR code should be part of.
362 ///
363 /// - `first_master_key` - Our own cross signing master key.
364 /// - `second_master_key` - The cross signing master key of the other user.
365 /// - `shared_secret` - A random bytestring encoded as unpadded base64,
366 /// needs to be at least 8 bytes long.
367 pub fn new(
368 flow_id: String,
369 first_master_key: Ed25519PublicKey,
370 second_master_key: Ed25519PublicKey,
371 shared_secret: Base64,
372 ) -> Self {
373 Self { flow_id, first_master_key, second_master_key, shared_secret }
374 }
375
376 /// Encode the `VerificationData` into a vector of bytes that can be encoded
377 /// as a QR code.
378 ///
379 /// The encoding can fail if the master keys that should be encoded are not
380 /// valid base64.
381 ///
382 /// # Examples
383 ///
384 /// ```
385 /// # use matrix_sdk_qrcode::{QrVerificationData, DecodingError};
386 /// # fn main() -> Result<(), DecodingError> {
387 /// let data = b"MATRIX\
388 /// \x02\x00\x00\x0f\
389 /// $test:localhost\
390 /// kS /\x92i\x1e6\xcd'g\xf9#\x11\xd8\x8a\xa2\xf61\x05\x1b6\xef\xfc\xa4%\x80\x1a\x0c\xd2\xe8\x04\
391 /// \xbdR|\xf8n\x07\xa4\x1f\xb4\xcc3\x0eBT\xe7[~\xfd\x87\xd06B\xdfoVv%\x9b\x86\xae\xbcM\
392 /// SHARED_SECRET";
393 ///
394 /// let result = QrVerificationData::from_bytes(data)?;
395 /// if let QrVerificationData::Verification(decoded) = result {
396 /// let encoded = decoded.to_bytes().unwrap();
397 /// assert_eq!(data.as_ref(), encoded.as_slice());
398 /// } else {
399 /// panic!("Data was encoded as an incorrect mode");
400 /// }
401 /// # Ok(())
402 /// # }
403 /// ```
404 pub fn to_bytes(&self) -> Result<Vec<u8>, EncodingError> {
405 to_bytes(
406 Self::QR_MODE,
407 self.flow_id.as_str(),
408 self.first_master_key,
409 self.second_master_key,
410 &self.shared_secret,
411 )
412 }
413
414 /// Encode the `VerificationData` into a `QrCode`.
415 ///
416 /// This method turns the `VerificationData` into a QR code that can be
417 /// rendered and presented to be scanned.
418 ///
419 /// The encoding can fail if the data doesn't fit into a QR code or if the
420 /// keys that should be encoded into the QR code are not valid base64.
421 pub fn to_qr_code(&self) -> Result<QrCode, EncodingError> {
422 to_qr_code(
423 Self::QR_MODE,
424 self.flow_id.as_str(),
425 self.first_master_key,
426 self.second_master_key,
427 &self.shared_secret,
428 )
429 }
430}
431
432impl From<VerificationData> for QrVerificationData {
433 fn from(data: VerificationData) -> Self {
434 Self::Verification(data)
435 }
436}
437
438/// The non-encoded data for the second mode of QR code verification.
439///
440/// This mode is used for verification between two devices of the same user
441/// where this device, that is creating this QR code, is trusting or owning the
442/// cross signing master key.
443#[derive(Clone, Debug, PartialEq, Eq)]
444pub struct SelfVerificationData {
445 transaction_id: String,
446 master_key: Ed25519PublicKey,
447 device_key: Ed25519PublicKey,
448 shared_secret: Base64,
449}
450
451impl SelfVerificationData {
452 const QR_MODE: u8 = 0x01;
453
454 /// Create a new `SelfVerificationData` struct that can be encoded as a QR
455 /// code.
456 ///
457 /// # Arguments
458 ///
459 /// - `transaction_id` - The transaction id of this verification flow, the
460 /// transaction id was sent by the `m.key.verification.request` event that
461 /// initiated the verification flow this QR code should be part of.
462 ///
463 /// - `master_key` - Our own cross signing master key.
464 /// - `device_key` - The ed25519 key of the other device.
465 /// - `shared_secret` - A random bytestring encoded as unpadded base64,
466 /// needs to be at least 8 bytes long.
467 pub fn new(
468 transaction_id: String,
469 master_key: Ed25519PublicKey,
470 device_key: Ed25519PublicKey,
471 shared_secret: Base64,
472 ) -> Self {
473 Self { transaction_id, master_key, device_key, shared_secret }
474 }
475
476 /// Encode the `SelfVerificationData` into a vector of bytes that can be
477 /// encoded as a QR code.
478 ///
479 /// The encoding can fail if the keys that should be encoded are not valid
480 /// base64.
481 ///
482 /// # Examples
483 ///
484 /// ```
485 /// # use matrix_sdk_qrcode::{QrVerificationData, DecodingError};
486 /// # fn main() -> Result<(), DecodingError> {
487 /// let data = b"MATRIX\
488 /// \x02\x01\x00\x06\
489 /// FLOWID\
490 /// kS /\x92i\x1e6\xcd'g\xf9#\x11\xd8\x8a\xa2\xf61\x05\x1b6\xef\xfc\xa4%\x80\x1a\x0c\xd2\xe8\x04\
491 /// \xbdR|\xf8n\x07\xa4\x1f\xb4\xcc3\x0eBT\xe7[~\xfd\x87\xd06B\xdfoVv%\x9b\x86\xae\xbcM\
492 /// SHARED_SECRET";
493 ///
494 /// let result = QrVerificationData::from_bytes(data)?;
495 /// if let QrVerificationData::SelfVerification(decoded) = result {
496 /// let encoded = decoded.to_bytes().unwrap();
497 /// assert_eq!(data.as_ref(), encoded.as_slice());
498 /// } else {
499 /// panic!("Data was encoded as an incorrect mode");
500 /// }
501 /// # Ok(())
502 /// # }
503 /// ```
504 pub fn to_bytes(&self) -> Result<Vec<u8>, EncodingError> {
505 to_bytes(
506 Self::QR_MODE,
507 &self.transaction_id,
508 self.master_key,
509 self.device_key,
510 &self.shared_secret,
511 )
512 }
513
514 /// Encode the `SelfVerificationData` into a `QrCode`.
515 ///
516 /// This method turns the `SelfVerificationData` into a QR code that can be
517 /// rendered and presented to be scanned.
518 ///
519 /// The encoding can fail if the data doesn't fit into a QR code or if the
520 /// keys that should be encoded into the QR code are not valid base64.
521 pub fn to_qr_code(&self) -> Result<QrCode, EncodingError> {
522 to_qr_code(
523 Self::QR_MODE,
524 &self.transaction_id,
525 self.master_key,
526 self.device_key,
527 &self.shared_secret,
528 )
529 }
530}
531
532impl From<SelfVerificationData> for QrVerificationData {
533 fn from(data: SelfVerificationData) -> Self {
534 Self::SelfVerification(data)
535 }
536}
537
538/// The non-encoded data for the third mode of QR code verification.
539///
540/// This mode is used for verification between two devices of the same user
541/// where this device, that is creating this QR code, is not trusting the cross
542/// signing master key.
543#[derive(Clone, Debug, PartialEq, Eq)]
544pub struct SelfVerificationNoMasterKey {
545 transaction_id: String,
546 device_key: Ed25519PublicKey,
547 master_key: Ed25519PublicKey,
548 shared_secret: Base64,
549}
550
551impl SelfVerificationNoMasterKey {
552 const QR_MODE: u8 = 0x02;
553
554 /// Create a new `SelfVerificationData` struct that can be encoded as a QR
555 /// code.
556 ///
557 /// # Arguments
558 ///
559 /// - `transaction_id` - The transaction id of this verification flow, the
560 /// transaction id was sent by the `m.key.verification.request` event that
561 /// initiated the verification flow this QR code should be part of.
562 ///
563 /// - `device_key` - The ed25519 key of our own device.
564 /// - `master_key` - Our own cross signing master key.
565 /// - `shared_secret` - A random bytestring encoded as unpadded base64,
566 /// needs to be at least 8 bytes long.
567 pub fn new(
568 transaction_id: String,
569 device_key: Ed25519PublicKey,
570 master_key: Ed25519PublicKey,
571 shared_secret: Base64,
572 ) -> Self {
573 Self { transaction_id, device_key, master_key, shared_secret }
574 }
575
576 /// Encode the `SelfVerificationNoMasterKey` into a vector of bytes that can
577 /// be encoded as a QR code.
578 ///
579 /// The encoding can fail if the keys that should be encoded are not valid
580 /// base64.
581 ///
582 /// # Examples
583 ///
584 /// ```
585 /// # use matrix_sdk_qrcode::{QrVerificationData, DecodingError};
586 /// # fn main() -> Result<(), DecodingError> {
587 /// let data = b"MATRIX\
588 /// \x02\x02\x00\x06\
589 /// FLOWID\
590 /// kS /\x92i\x1e6\xcd'g\xf9#\x11\xd8\x8a\xa2\xf61\x05\x1b6\xef\xfc\xa4%\x80\x1a\x0c\xd2\xe8\x04\
591 /// \xbdR|\xf8n\x07\xa4\x1f\xb4\xcc3\x0eBT\xe7[~\xfd\x87\xd06B\xdfoVv%\x9b\x86\xae\xbcM\
592 /// SHARED_SECRET";
593 ///
594 /// let result = QrVerificationData::from_bytes(data)?;
595 /// if let QrVerificationData::SelfVerificationNoMasterKey(decoded) = result {
596 /// let encoded = decoded.to_bytes().unwrap();
597 /// assert_eq!(data.as_ref(), encoded.as_slice());
598 /// } else {
599 /// panic!("Data was encoded as an incorrect mode");
600 /// }
601 /// # Ok(())
602 /// # }
603 /// ```
604 pub fn to_bytes(&self) -> Result<Vec<u8>, EncodingError> {
605 to_bytes(
606 Self::QR_MODE,
607 &self.transaction_id,
608 self.device_key,
609 self.master_key,
610 &self.shared_secret,
611 )
612 }
613
614 /// Encode the `SelfVerificationNoMasterKey` into a `QrCode`.
615 ///
616 /// This method turns the `SelfVerificationNoMasterKey` into a QR code that
617 /// can be rendered and presented to be scanned.
618 ///
619 /// The encoding can fail if the data doesn't fit into a QR code or if the
620 /// keys that should be encoded into the QR code are not valid base64.
621 pub fn to_qr_code(&self) -> Result<QrCode, EncodingError> {
622 to_qr_code(
623 Self::QR_MODE,
624 &self.transaction_id,
625 self.device_key,
626 self.master_key,
627 &self.shared_secret,
628 )
629 }
630}
631
632impl From<SelfVerificationNoMasterKey> for QrVerificationData {
633 fn from(data: SelfVerificationNoMasterKey) -> Self {
634 Self::SelfVerificationNoMasterKey(data)
635 }
636}