Generates a Secure Join QR code. With `chat` set to `None` this generates a setup-contact QR code, with `chat` set to a [`ChatId`] generates a join-group/join-broadcast-channel QR code for the given chat.
(context: &Context, chat: Option<ChatId>)
| 87 | /// With `chat` set to `None` this generates a setup-contact QR code, with `chat` set to a |
| 88 | /// [`ChatId`] generates a join-group/join-broadcast-channel QR code for the given chat. |
| 89 | pub async fn get_securejoin_qr(context: &Context, chat: Option<ChatId>) -> Result<String> { |
| 90 | /*======================================================= |
| 91 | ==== Alice - the inviter side ==== |
| 92 | ==== Step 1 in "Setup verified contact" protocol ==== |
| 93 | =======================================================*/ |
| 94 | |
| 95 | ensure_secret_key_exists(context).await.ok(); |
| 96 | |
| 97 | let chat = match chat { |
| 98 | Some(id) => { |
| 99 | let chat = Chat::load_from_db(context, id).await?; |
| 100 | ensure!( |
| 101 | chat.typ == Chattype::Group || chat.typ == Chattype::OutBroadcast, |
| 102 | "Can't generate SecureJoin QR code for chat {id} of type {}", |
| 103 | chat.typ |
| 104 | ); |
| 105 | if chat.grpid.is_empty() { |
| 106 | let err = format!("Can't generate QR code, chat {id} is a email thread"); |
| 107 | error!(context, "get_securejoin_qr: {}.", err); |
| 108 | bail!(err); |
| 109 | } |
| 110 | if chat.typ == Chattype::OutBroadcast { |
| 111 | // If the user created the broadcast before updating Delta Chat, |
| 112 | // then the secret will be missing, and the user needs to recreate the broadcast: |
| 113 | if load_broadcast_secret(context, chat.id).await?.is_none() { |
| 114 | error!( |
| 115 | context, |
| 116 | "Not creating securejoin QR for old broadcast {}, see chat for more info.", |
| 117 | chat.id, |
| 118 | ); |
| 119 | let text = BROADCAST_INCOMPATIBILITY_MSG; |
| 120 | add_info_msg(context, chat.id, text).await?; |
| 121 | bail!(text.to_string()); |
| 122 | } |
| 123 | } |
| 124 | Some(chat) |
| 125 | } |
| 126 | None => None, |
| 127 | }; |
| 128 | let grpid = chat.as_ref().map(|c| c.grpid.as_str()); |
| 129 | // Invite number is used to request the inviter key. |
| 130 | let invitenumber = token::lookup_or_new(context, Namespace::InviteNumber, grpid).await?; |
| 131 | |
| 132 | // Auth token is used to verify the key-contact |
| 133 | // if the token is not old |
| 134 | // and add the contact to the group |
| 135 | // if there is an associated group ID. |
| 136 | // |
| 137 | // We always generate a new auth token |
| 138 | // because auth tokens "expire" |
| 139 | // and can only be used to join groups |
| 140 | // without verification afterwards. |
| 141 | let auth = create_id(); |
| 142 | token::save(context, Namespace::Auth, grpid, &auth, time()).await?; |
| 143 | |
| 144 | let fingerprint = self_fingerprint(context).await?; |
| 145 | |
| 146 | let self_addr = context.get_primary_self_addr().await?; |