react-native-matrix-crypto
    Preparing search index...

    Function requestSelfVerification

    • Asks this account's other devices to verify this one, so that this device can join the cross-signing identity the account already has.

      This is what a second login does. A device that does not hold the account's private signing keys joins the identity; it does not create one. bootstrapCrossSigning refuses such a device with 'identity_already_exists', and that refusal is the one thing standing between an ordinary second login and an account whose identity has been silently replaced, resetting the trust of every device and every person who had verified it. This call is the remedy that refusal points at, and it is not a way around it.

      Three ways it differs from requestVerification

      It names no device, because a new login is in no position to choose one. The invitation goes to every other device of yours that the account's identity has signed, and whichever is in front of a person answers first; the others are told the flow was taken. A device of yours that the identity has never signed is not invited, which is deliberate: it is a login this account's identity has never vouched for.

      The signature at the end is made with a different key, and by the other side. The device that already holds the private keys signs this one with the account's self-signing key. This device has nothing to sign with yet, which is the whole reason it is asking.

      It asks for the account's secrets, which verifying somebody else never does. Once the comparison completes, this library asks your other devices for the cross-signing seeds it lacks. Those go out as ordinary entries in takeOutgoingRequests' output, and the encrypted answer arrives in a later receiveSyncChanges, which imports it.

      Nothing returns to you when the seeds land

      The call that started all this resolved long before. Two things tell you it happened, and you want the first:

      • onCryptoSignal announces 'trust_changed' for your own user id on the sync that carried the seeds. That is the signal to read getIdentityStatus again. It is the same variant a completed comparison produces, so read the status rather than counting signals; see onCryptoSignal's own comment.
      • getIdentityStatus is the durable answer: privateKeysHeld === true means this device can now sign with the account's identity rather than only recognise it. Read it when you are told to, not on a timer.

      Driving the flow

      Identical to requestVerification from the moment this resolves, by either method. By short string: pump, wait for getVerificationStage to read 'ready', startVerificationComparison, pump, read getVerificationMaterial, show it, and confirmVerification or cancelVerification. The person is comparing two of their own screens instead of talking to somebody else, which changes none of the calls.

      By a scanned code, if the product asked for one, the person points one of their own phones at the other instead of reading symbols off both, and this is where that is most natural, because both screens are already in front of them. Both self modes work: the established device may show the code and the new login read it, or the other way round, and which happens is decided by which phone is held up rather than by anything you pass. Showing a code needs none of the account's private signing keys, which is what makes it reachable on the device that is joining. See offerScannableCodes and getVerificationCode.

      Including the one sync between two verifications, which for this call means your own account: a second self-verification opened without a receiveSyncChanges after the first comes back already cancelled. requestVerification says why, and the reason is the layer underneath rather than anything either call does.

      Refusals

      'account_keys_not_fetched' means this process has not yet asked the server about this account, so it cannot know whether there is an identity to join. This call queues that key query before returning the refusal, so the remedy is the ordinary loop: drain the pump, send, report sent, and call this again. You do not have to reach for bootstrapCrossSigning to get unstuck, and on a device that is joining you should not: it is the call that would create a second identity if the state ever moved under you.

      Expect this refusal on every launch, not only the first. Whether the server has been asked is not persisted, and the layer underneath will not volunteer the question for an account it already knows about, so a relaunched store starts out having asked nothing.

      'identity_not_known' means one of two things, and getIdentityStatus().identityPublicationPending tells them apart. False: the server was asked and said this account has no identity, so there is nothing to join and no retry helps. True: this device holds an identity it minted that no homeserver has ever asserted back, so there is nothing yet for another device to join it to, and the flow would sign under an identity the account may never have.

      createCrossSigningIdentity is the call for both, and for the same reason each time: creating a first identity and finishing a publication that was interrupted are the same decision, and it is one your product makes rather than something this handler calls. This is the same refusal, with the same remedy, that bootstrapCrossSigning reports. The paragraph used to name bootstrapCrossSigning as the answer, which stopped being true when creating became its own call and left the two surfaces saying different things about one error, and it used to give only the first of the two meanings, which stopped being true when the gate gained its second condition.

      Returns Promise<string>