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