Skip to content

TMR Accesses

Le concept des TmrAccesses est une fonctionnalité du SDK Seald qui permet de récupérer une EncryptionSession par un mécanisme de 2-man rule, comme pour le stockage des identités.

L'idée est de protéger une EncryptionSession pour un certain Auth Factor (une adresse email, ou un numéro de téléphone), avec une certaine overEncryptionKey qui sera stockée par vos serveurs (comme la twoManRuleKey pour le stockage des identités).

Ensuite, lorsqu'il veut la récupérer, le destinataire reçoit un challenge par email ou SMS, valable 6h, et doit le répéter dans l'application pour prouver qu'il maitrise le Auth Factor, et peut accéder à la EncryptionSession.

Cette fonctionnalité est particulièrement utile pour ajouter comme destinataire à une EncryptionSession un utilisateur qui n'est pas encore inscrit sur votre application, par exemple au moment de lui envoyer une invitation.

Création d'un TmrAccess

L'utilisateur qui a créé une EncryptionSession, ou tout utilisateur y ayant accès et qui a le droit forward, peut créer un TmrAccess pour cette EncryptionSession.

Pour créer un TmrAccess, il faut récupérer l'objet EncryptionSession, et utiliser la méthode session.addTmrAccess(). Cette méthode prend comme argument tmrRecipients, qui est un Array de TmrRecipientWithRights. Chaque élément de cet Array contient trois champs :

  • authFactor, qui lui même contient le type de l'Auth Factor utilisé ('EM' pour une adresse email, 'SMS' pour un numéro de téléphone), et la valeur de cet Auth Factor ;
  • rawOverEncryptionKey, qui est la clé à utiliser pour protéger ce TmrAccess, doit absolument être l'encodage en base64 d'un buffer cryptographiquement aléatoire de 64 octets ;
  • optionnellement, rights qui définit les droits pour ce TmrAccess.

TIP

Afin d'assurer la confidentialité end-to-end, la rawOverEncryptionKey doit n'être accessible qu'à la personne qui crée le TmrAccess et au destinataire de la session.

Il est de la responsabilité de votre serveur de stocker ces rawOverEncryptionKey et d'en limiter l'accès à l'utilisateur qui crée le TmrAccess et l'utilisateur invité.

Si plusieurs utilisateurs doivent ajouter des TmrAccesses à destination du même Auth Factor, il convient de créer des rawOverEncryptionKeys différentes pour chacun. Vous pouvez également créer une rawOverEncryptionKey différente pour chaque ajout de TmrAccess, même si c'est le même utilisateur qui l'ajoute pour le même Auth Factor, si cela est plus simple pour vous.

Vous pouvez également spécifier des droits pour le destinataire de ce TmrAccess avec l'argument rights. Lorsque l'utilisateur convertit un TmrAccess en accès normal, ces droits seront convertis avec.

TIP

Les rights par défaut pour un TmrAccess sont { read: true, forward: true, revoke: false }.

La méthode session.addTmrAccess() rend l'ID du TmrAccess créé. Cet ID n'est pas secret, et peut être transmis à votre serveur. Il peut servir à administrer le TmrAccess, ou encore à choisir quel TmrAccess utiliser pour récupérer une session.

Exemple d'utilisation :

javascript
// Chaque `rawOverEncryptionKey` doit nécessairement être un buffer de 64 octets aléatoires cryptographiquement sécurisé, encodé en base64.
const rawOverEncryptionKey = await sealdSdk.utils.generateB64EncodedSymKey()

// Création des `TmrAccess`
const tmrAccessId = await session.addTmrAccess({
  authFactor: { type: 'EM', value: 'test@example.com' },
  rawOverEncryptionKey,
  rights: { read: true, forward: false, revoke: false }
})

// Maintenant, vous pouvez envoyer le tmrAccessId avec la rawOverEncryptionKey à vos serveurs pour les enregistrer.
// Chaque `rawOverEncryptionKey` doit nécessairement être un buffer de 64 octets aléatoires cryptographiquement sécurisé, encodé en base64.
const rawOverEncryptionKey = await sealdSdk.utils.generateB64EncodedSymKey()

// Création des `TmrAccess`
const tmrAccessId = await session.addTmrAccess({
  authFactor: { type: 'EM', value: 'test@example.com' },
  rawOverEncryptionKey,
  rights: { read: true, forward: false, revoke: false }
})

// Maintenant, vous pouvez envoyer le tmrAccessId avec la rawOverEncryptionKey à vos serveurs pour les enregistrer.

TIP

Si vous avez besoin d'ajouter plusieurs TmrAccesses à la même EncryptionSession, pour plusieurs Auth Factors destinataires par exemple, vous pouvez également utiliser la méthode session.addMultipleTmrAccesses(). Celle-ci à un type de retour plus complexe, détaillé dans sa référence.

Récupération d'une session avec un TmrAccess

Pour récupérer une EncryptionSession via un TmrAccess, il faut d'abord prouver que l'on contrôle le Auth Factor destinataire de celui-ci. Pour ceci, il faut récupérer un JWT depuis le serveur SSKS avec la méthode ssks2MR.getFactorToken(). Cette méthode nécessite bien entendu d'être authentifié auprès de SSKS, c'est-à-dire soit d'avoir déjà un authenticatedSessionId, soit d'utiliser le point d'API POST /tmr/back/challenge_send/ (avec force_auth à true) pour obtenir un challenge, et passer ce challenge lors de l'appel à ssks2MR.getFactorToken().

Ensuite, une fois qu'on a ce token, il faut utiliser la méthode sdk.retrieveEncryptionSessionByTmr(). Cette méthode prend comme arguments :

  • l'ID de l'EncryptionSession ;
  • le token rendu par ssks2MR.getFactorToken() ;
  • la rawOverEncryptionKey utilisée ;
  • optionnellement, des options (notamment de filtrage) détaillées plus bas.

La méthode sdk.retrieveEncryptionSessionByTmr() rend une EncryptionSession, qui permet ensuite de chiffrer/déchiffrer des messages et fichiers.

TIP

Si vous accédez à une EncryptionSession via un TmrAccess, vous ne pouvez pas utiliser les méthodes de gestions d'accès de celle-ci (session.addRecipients(), session.addSymEncKey(), session.revokeRecipients(), session.listRecipients(), ...) sans l'avoir convertie.

Exemple d'utilisation simple :

javascript
// Récupération d'un tmrJWT
const getFactorTokenResponse = await sdk.ssks2MR.getFactorToken({ sessionId: ssksSessionId, authFactor, challenge })

// Récupération d'une EncryptionSession avec un `TmrAccess`
const encryptionSession = await sdk.retrieveEncryptionSessionByTmr(
  encryptionSessionId, // `encryptionSessionId` n'est pas secret, et peut être transmis via votre serveur
  getFactorTokenResponse.token, // Le token obtenu par l'appel de `ssks2MR.getFactorToken()`
  rawOverEncryptionKey // `rawOverEncryptionKey` transmis par votre serveur
)
// Récupération d'un tmrJWT
const getFactorTokenResponse = await sdk.ssks2MR.getFactorToken({ sessionId: ssksSessionId, authFactor, challenge })

// Récupération d'une EncryptionSession avec un `TmrAccess`
const encryptionSession = await sdk.retrieveEncryptionSessionByTmr(
  encryptionSessionId, // `encryptionSessionId` n'est pas secret, et peut être transmis via votre serveur
  getFactorTokenResponse.token, // Le token obtenu par l'appel de `ssks2MR.getFactorToken()`
  rawOverEncryptionKey // `rawOverEncryptionKey` transmis par votre serveur
)

Attention, si il existe plusieurs TmrAccesses pour le même Auth Factor et la même EncryptionSession, par défaut retrieveEncryptionSessionByTmr() renverra une erreur. En effet, cette fonction doit savoir quel TmrAccess utiliser, c'est-à-dire lequel correspond à la rawOverEncryptionKey passée.

Pour cela, retrieveEncryptionSessionByTmr() accepte un objet d'options, qui contient les options facultatives suivantes :

  • useCache : un booléen, qui est par défaut à true. Indique d'essayer de récupérer la session dans le cache ;
  • tmrAccessId : l'ID du TmrAccess à utiliser. Si vous l'avez, il est recommandé de le passer systématiquement, pour éviter tout problème ;
  • createdById : l'ID de l'utilisateur qui a ajouté le TmrAccess à utiliser ;
  • tryIfMultiple : un booléen, qui est par défaut à false. Si mis à true, et si les autres filtres éventuels passés correspondent à plusieurs TmrAccesses, indique d'itérer sur tous les TmrAccesses récupérés pour trouver sur lequel la rawOverEncryptionKey passée fonctionne, au lieu de renvoyer une erreur.

Exemple d'utilisation avec options :

javascript
// Récupération d'un tmrJWT
const getFactorTokenResponse = await sdk.ssks2MR.getFactorToken({ sessionId: ssksSessionId, authFactor, challenge }) 

// Récupération d'une EncryptionSession avec un `TmrAccess`
const encryptionSession = await sdk.retrieveEncryptionSessionByTmr(
  encryptionSessionId, // `encryptionSessionId` n'est pas secret, et peut être transmis via votre serveur
  getFactorTokenResponse.token, // Le token obtenu par l'appel de `ssks2MR.getFactorToken()`
  rawOverEncryptionKey, // `rawOverEncryptionKey` transmis par votre serveur
  {
    tmrAccessId // récupère la session via le TmrAccess qui correspond à cet ID
  }
)
// Récupération d'un tmrJWT
const getFactorTokenResponse = await sdk.ssks2MR.getFactorToken({ sessionId: ssksSessionId, authFactor, challenge }) 

// Récupération d'une EncryptionSession avec un `TmrAccess`
const encryptionSession = await sdk.retrieveEncryptionSessionByTmr(
  encryptionSessionId, // `encryptionSessionId` n'est pas secret, et peut être transmis via votre serveur
  getFactorTokenResponse.token, // Le token obtenu par l'appel de `ssks2MR.getFactorToken()`
  rawOverEncryptionKey, // `rawOverEncryptionKey` transmis par votre serveur
  {
    tmrAccessId // récupère la session via le TmrAccess qui correspond à cet ID
  }
)

Convertir des TmrAccesses en accès normaux

Vous pouvez aussi convertir un TmrAccess en accès normal à l'EncryptionSession correspondante. Ce mécanisme peut être utile si le TmrAccess a été créé en tant qu'invitation d'un utilisateur qui n'a pas encore de compte Seald à accéder à une EncryptionSession. Une fois que celui-ci a créé son compte Seald, les TmrAccesses lui étant destinés peuvent être convertis en accès normaux, pour que son compte Seald puisse à l'avenir accéder aux EncryptionSessions correspondantes sans passer par une authentification 2-Man-Rule à chaque fois.

Afin de convertir un TmrAccess en accès normal à l'EncryptionSession, il faut d'abord prouver que l'on contrôle le Auth Factor destinataire de celui-ci. Pour ceci, il faut récupérer un JWT depuis le serveur SSKS avec la méthode ssks2MR.getFactorToken(). Cette méthode nécessite bien entendu d'être authentifié auprès de SSKS, c'est à dire soit d'avoir déjà un authenticatedSessionId, soit d'utiliser le point d'API POST /tmr/back/challenge_send/ (avec force_auth à true) pour obtenir un challenge, et passer ce challenge lors de l'appel à ssks2MR.getFactorToken().

Ensuite, une fois qu'on a ce token, il faut utiliser la méthode sdk.convertTmrAccesses(). Cette méthode prend comme arguments :

  • le token rendu par ssks2MR.getFactorToken() ;
  • la rawOverEncryptionKey utilisée ;
  • optionnellement, des options (notamment de filtrage) détaillées plus bas.

Cette méthode récupère tous les TmrAccesses correspondants aux filtres données, et les convertit en accès normal à l'EncryptionSession correspondante.

WARNING

Attention, il faut absolument que tous les TmrAccesses qui correspondent à ces filtres soient protégés par la même rawOverEncryptionKey !

Pour cela, convertTmrAccesses() accepte un objet d'options, qui contient les options facultatives suivantes :

  • deleteOnConvert : un booléen, qui est par défaut à true. Indique de supprimer les TmrAccesses après leur conversion en accès normaux ;
  • sessionId : l'ID de l'EncryptionSession pour laquelle convertir un TmrAccess ;
  • tmrAccessId : l'ID du TmrAccess à convertir ;
  • createdById : l'ID de l'utilisateur qui a ajouté les TmrAccesses à convertir.

TIP

Puisqu'il est recommandé d'avoir une rawOverEncryptionKey différente pour chaque émetteur, et que l'appel à convertTmrAccesses() doit absolument contenir des filtres qui le limitent à des TmrAccesses ayant la même rawOverEncryptionKey, il est recommandé de toujours spécifier createdById.

Exemple d'utilisation :

javascript
// Récupération d'un tmrJWT
const getFactorTokenResponse = await sdk.ssks2MR.getFactorToken({ sessionId: ssksSessionId, authFactor, challenge })

// Conversion des TmrAccesses
const result = await sdk.convertTmrAccesses(
  getFactorTokenResponse.token, // Le token obtenu par l'appel de `ssks2MR.getFactorToken()`
  rawOverEncryptionKey, // `rawOverEncryptionKey` transmis par votre serveur
  {
    createdById, // convertit seulement les TmrAccesses créées par l'utilisateur correspondant à ce sealdID
    sessionId: encryptionSessionId // convertit seulement les TmrAccesses correspondant à cette EncryptionSession
  }
)

// On peut ici vérifier `result` pour vérifier si la conversion a réussi

// Maintenant, l'utilisateur peut récupérer la session directement
const encryptionSession = await sdk.retrieveEncryptionSession({ sessionId: encryptionSessionId })
// Récupération d'un tmrJWT
const getFactorTokenResponse = await sdk.ssks2MR.getFactorToken({ sessionId: ssksSessionId, authFactor, challenge })

// Conversion des TmrAccesses
const result = await sdk.convertTmrAccesses(
  getFactorTokenResponse.token, // Le token obtenu par l'appel de `ssks2MR.getFactorToken()`
  rawOverEncryptionKey, // `rawOverEncryptionKey` transmis par votre serveur
  {
    createdById, // convertit seulement les TmrAccesses créées par l'utilisateur correspondant à ce sealdID
    sessionId: encryptionSessionId // convertit seulement les TmrAccesses correspondant à cette EncryptionSession
  }
)

// On peut ici vérifier `result` pour vérifier si la conversion a réussi

// Maintenant, l'utilisateur peut récupérer la session directement
const encryptionSession = await sdk.retrieveEncryptionSession({ sessionId: encryptionSessionId })