Skip to content

Commit

Permalink
Merge branch 'develop' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
yn4v4s committed Jan 28, 2022
2 parents 16b2550 + cc07bb8 commit e429d15
Show file tree
Hide file tree
Showing 27 changed files with 918 additions and 5 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module.exports = {
},
rules: {
'prettier/prettier': 'error',
'@typescript-eslint/no-non-null-assertion': 'off',
},
plugins: ['@typescript-eslint', 'prettier'],
};
101 changes: 101 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,102 @@
# Telegram Passport

### Parse/Decrypt incoming [Telegram Passport](https://core.telegram.org/passport) data<br/><br/>

#### \* Note: All the type definitions on this library are in compliance with those defined in the Telegram API specification<br/><br/>

## What does this library do?

### Provided your Bot's Private Key, this library will:

- Decrypt the [EncryptedCredentials](https://core.telegram.org/bots/api#encryptedcredentials) object from the `credentials` field in [PassportData](https://core.telegram.org/bots/api#passportdata)
- Parse the fields on each [EncryptedPassportElement](https://core.telegram.org/bots/api#encryptedpassportelement) from the `data` field in PassportData
- Decrypt de `data` field (if present) from the EncryptedPassportElement
- Validate the integrity of the decryted data

## What doesn't this library do?

- Get the encrypted files corresponding to the requested fields<br/>\* Download the encrypted files using the [getFile](https://core.telegram.org/bots/api#getfile) API endpoint, then use the `decryptData` method to decrypt them
<br/><br/>

## Usage

- First, create a new instance of the `TelegramPassport` class

```
const telegramPassport = new TelegramPassport(<bot_private_key>);
```

- Parse and decryp de data of all the elements shared with the bot

```
const data = telegramPassport.decryptPassportData(update.message.passport_data);
```

#### \* `update` is the object representing the incoming [Update](https://core.telegram.org/bots/api#update) that was sent to the Bot<br/><br/>

- Decryting files

```
/*
get the data corresponding to the file you want to decryp
for example, the front side of the id card
*/
const id_frontSide = data.identity_card.front_side;
// download the file using the getFile API endpoint
...
// decryp the file
const file = telegramPassport.decryptData(
<downloaded_file_data>,
id_fronSide.secret,
id_fronSide.file_hash,
);
```

- Depending on the fields you requested, you might not need to process the whole `PassportData` object; for example, the "phone_number" and "email" fields are not encrypted. Thus, you only need to decrypt the credentials to obtain the nonce, then, you can get "phone_number" and "email" from `passport_data.data`

```
/*
in this case, data will look like this
data: [
{
"type": "phone_number",
"phone_number": "XXXXXXXXXXX",
"hash": "the_base64-encoded_hash",
},
{
"type": "email",
"email": "johndoe@example.com",
"hash": "the_base64-encoded_hash"
},
]
*/
// decrypt the credentials
const credentials = telegramPassport.decryptPassportCredentials(
update.message.passport_data.credentials,
);
```

#### \* `update` is the object representing the incoming [Update](https://core.telegram.org/bots/api#update) that was sent to the Bot<br/><br/>

## What can be inproved?

- The type "handling" in the `decryptData` method<br/>\* Need a TS guru that can give me a hand with that, go check the code<br/><br/>

## Found a bug?

### Open an [issue](https://github.com/merqva/telegram-passport/issues) (PRs are welcome)

#### \* be patient, I might be busy<br/><br/>

## Stay in touch

- Author - [Yoel Navas](mailto:yn4v4s@gmail.com)
- Website - [merqva.com](https://merqva.com/)
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@merqva/telegram-passport",
"version": "0.0.1",
"version": "1.0.0",
"description": "Decrypt/Parse incoming Telegram Passport data",
"main": "dist/cjs/index.js",
"module": "dist/esm/index.js",
Expand Down
3 changes: 3 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export enum ErrorMessages {
ERR_DATA_INTEGRITY_CHECK_FAILED = 'The integrity of the data could not be verified; hashes do not match',
}
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { TelegramPassport } from './telegram-passport'
export { TelegramPassport } from './telegram-passport';
export * from './interfaces';
21 changes: 21 additions & 0 deletions src/interfaces/bill-like.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { FileCredentials, PassportFile } from '.';
/**
* Object signature for the requested "utility_bill".
* @see [Fields](https://core.telegram.org/passport#fields)
*
* It is used to define "bank_statement", "rental_agreement", "passport_registration"
* and "temporary_registration" too, since they share the same signature.
*
* @interface BillLike
*/
export interface BillLike {
/**
* Array of documents with credentials merged into it
*/
files: Array<PassportFile & FileCredentials>;

/**
* Optional. Array of certified english translations of the documents, with credentials merged into it
*/
translation?: Array<PassportFile & FileCredentials>;
}
19 changes: 19 additions & 0 deletions src/interfaces/credentials.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { SecureData } from '.';

/**
* Credentials is a JSON-serialized object
* @see [Credentials](https://core.telegram.org/passport#credentials)
* @interface Credentials
*/
export interface Credentials {
/**
* Credentials for encrypted data
*/
secure_data: SecureData;

/**
* Bot-specified nonce.
* IMPORTANT: Make sure that the nonce is the same as was passed in the request
*/
nonce: string;
}
16 changes: 16 additions & 0 deletions src/interfaces/data-credentials.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* These credentials can be used to decrypt encrypted data from the data field in EncryptedPassportElement
* @see [DataCredentials](https://core.telegram.org/passport#datacredentials)
* @interface DataCredentials
*/
export interface DataCredentials {
/**
* Checksum of encrypted data
*/
data_hash: string;

/**
* Secret of encrypted data
*/
secret: string;
}
17 changes: 17 additions & 0 deletions src/interfaces/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { IdDocumentData, PersonalDetails, ResidentialAddress } from '.';

/**
* Represents the data key on those fields that contain a data key
* like "personal_details", "passport", "internal_passport", "driver_license",
* "identity_card" and "address"
* @see [Fields](https://core.telegram.org/passport#fields)
* @interface Data
*/
export interface Data<
T extends IdDocumentData | PersonalDetails | ResidentialAddress,
> {
/**
* data key, can only be of type IdDocumentData, PersonalDetails or ResidentialAddress
*/
data: T;
}
22 changes: 22 additions & 0 deletions src/interfaces/encrypted-credentials.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* Contains data required for decrypting and authenticating EncryptedPassportElement
* @see [EncryptedCredentials](https://core.telegram.org/bots/api#encryptedcredentials)
* @interface EncryptedCredentials
*/
export interface EncryptedCredentials {
/**
* Base64-encoded encrypted JSON-serialized data with unique user's payload, data
* hashes and secrets required for `EncryptedPassportElement` decryption and authentication
*/
data: string;

/**
* Base64-encoded data hash for data authentication
*/
hash: string;

/**
* Base64-encoded secret, encrypted with the bot's public RSA key, required for data decryption
*/
secret: string;
}
76 changes: 76 additions & 0 deletions src/interfaces/encrypted-passport-element.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { EncryptedPassportElementType } from '../utils';
import { PassportFile } from '.';

/**
* Contains information about documents or other Telegram Passport elements shared with the bot by the user
* @see [EncryptedPassportElement](https://core.telegram.org/bots/api#encryptedpassportelement)
* @interface EncryptedPassportElement
*/
export interface EncryptedPassportElement {
/**
* Element type. One of "personal_details", "passport", "driver_license", "identity_card", "internal_passport",
* "address", "utility_bill", "bank_statement", "rental_agreement", "passport_registration",
* "temporary_registration", "phone_number", "email"
*/
type: EncryptedPassportElementType;

/**
* Optional. Base64-encoded encrypted Telegram Passport element data provided by the user.
* Available for "personal_details”, "passport", "driver_license", "identity_card", "internal_passport"
* and "address" types. Can be decrypted and verified using the accompanying `EncryptedCredentials`
*/
data?: string;

/**
* Optional. User's verified phone number, available only for "phone_number" type
*/
phone_number?: string;

/**
* Optional. User's verified email address, available only for "email" type
*/
email?: string;

/**
* Optional. Array of encrypted files with documents provided by the user.
* Available for "utility_bill", "bank_statement", "rental_agreement", "passport_registration"
* and "temporary_registration" types.
* Files can be decrypted and verified using the accompanying `EncryptedCredentials`
*/
files?: Array<PassportFile>;

/**
* Optional. Encrypted file with the front side of the document, provided by the user.
* Available for "passport", "driver_license", "identity_card" and "internal_passport".
* The file can be decrypted and verified using the accompanying `EncryptedCredentials`
*/
front_side?: PassportFile;

/**
* Optional. Encrypted file with the reverse side of the document, provided by the user.
* Available for "driver_license" and "identity_card".
* The file can be decrypted and verified using the accompanying `EncryptedCredentials`
*/
reverse_side?: PassportFile;

/**
* Optional. Encrypted file with the selfie of the user holding a document, provided by the user.
* Available for "passport", "driver_license", "identity_card" and "internal_passport".
* The file can be decrypted and verified using the accompanying `EncryptedCredentials`
*/
selfie?: PassportFile;

/**
* Optional. Array of encrypted files with translated versions of documents provided by the user.
* Available if requested for "passport", "driver_license", "identity_card", "internal_passport",
* "utility_bill", "bank_statement", "rental_agreement", "passport_registration"
* and "temporary_registration" types.
* Files can be decrypted and verified using the accompanying `EncryptedCredentials`
*/
translation?: Array<PassportFile>;

/**
* Base64-encoded element hash for using in `PassportElementErrorUnspecified`
*/
hash: string;
}
17 changes: 17 additions & 0 deletions src/interfaces/file-credentials.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* These credentials can be used to decrypt encrypted files from the front_side, reverse_side, selfie,
* files and translation fields in EncryptedPassportElement
* @see [FileCredentials](https://core.telegram.org/passport#filecredentials)
* @interface FileCredentials
*/
export interface FileCredentials {
/**
* Checksum of encrypted file
*/
file_hash: string;

/**
* Secret of encrypted file
*/
secret: string;
}
16 changes: 16 additions & 0 deletions src/interfaces/id-document-data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* This object represents the data of an identity document
* @see [IdDocumentData](https://core.telegram.org/passport#iddocumentdata)
* @interface IdDocumentData
*/
export interface IdDocumentData {
/**
* Document number
*/
document_no: string;

/**
* Optional. Date of expiry, in DD.MM.YYYY format
*/
expiry_date?: string;
}
29 changes: 29 additions & 0 deletions src/interfaces/id-document.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Data, FileCredentials, IdDocumentData, PassportFile } from '.';

/**
* Object signature for the requested "passport", "internal_passport", "driver_license"
* and "identity_card"
* @see [Fields](https://core.telegram.org/passport#fields)
* @interface IdDocument
*/
export interface IdDocument extends Data<IdDocumentData> {
/**
* Front side of the document with credentials merged into it
*/
front_side: PassportFile & FileCredentials;

/**
* Reverse side of the document with credentials merged into it
*/
reverse_side: PassportFile & FileCredentials;

/**
* Selfie of the user holding the document, with credentials merged into it
*/
selfie?: PassportFile & FileCredentials;

/**
* Optional. Array of certified english translations of the document, with credentials merged into it
*/
translation?: Array<PassportFile & FileCredentials>;
}
Loading

0 comments on commit e429d15

Please sign in to comment.