2020-01-09 15:27:00 +00:00
package telegram
import "errors"
/ *
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/rsa"
"crypto/sha1" //nolint: gosec
"crypto/sha256"
"crypto/sha512"
"encoding/base64"
* /
type (
2020-01-10 05:23:55 +00:00
// PassportData contains information about Telegram Passport data shared with the bot by the user.
2020-01-09 15:27:00 +00:00
PassportData struct {
2020-01-10 05:23:55 +00:00
// Array with information about documents and other Telegram Passport elements that was shared with the bot
2020-01-09 15:27:00 +00:00
Data [ ] * EncryptedPassportElement ` json:"data" `
// Encrypted credentials required to decrypt the data
Credentials * EncryptedCredentials ` json:"credentials" `
}
2020-01-10 05:23:55 +00:00
// PassportFile represents a file uploaded to Telegram Passport. Currently all Telegram Passport files are in JPEG format when decrypted and don't exceed 10MB.
2020-01-09 15:27:00 +00:00
PassportFile struct {
// Identifier for this file, which can be used to download or reuse the file
FileID string ` json:"file_id" `
// Unique identifier for this file, which is supposed to be the same over time and for different bots. Can't be used to download or reuse the file.
FileUniqueID string ` json:"file_unique_id" `
// File size
FileSize int ` json:"file_size" `
// Unix time when the file was uploaded
FileDate int ` json:"file_date" `
}
2020-01-10 05:23:55 +00:00
// EncryptedPassportElement contains information about documents or other Telegram Passport elements shared with the bot by the user.
2020-01-09 15:27:00 +00:00
EncryptedPassportElement struct {
// Element type.
Type string ` json:"type" `
2020-01-10 05:23:55 +00:00
// Base64-encoded encrypted Telegram Passport element data provided by the user, available for "personal_details", "passport", "driver_license", "identity_card", "identity_passport" and "address" types. Can be decrypted and verified using the accompanying EncryptedCredentials.
2020-01-09 15:27:00 +00:00
Data string ` json:"data,omitempty" `
// User's verified phone number, available only for "phone_number" type
PhoneNumber string ` json:"phone_number,omitempty" `
// User's verified email address, available only for "email" type
Email string ` json:"email,omitempty" `
2020-01-10 05:23:55 +00:00
// 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.
2020-01-09 15:27:00 +00:00
Files [ ] * PassportFile ` json:"files,omitempty" `
2020-01-10 05:23:55 +00:00
// 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.
2020-01-09 15:27:00 +00:00
FrontSide * PassportFile ` json:"front_side,omitempty" `
2020-01-10 05:23:55 +00:00
// 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.
2020-01-09 15:27:00 +00:00
ReverseSide * PassportFile ` json:"reverse_side,omitempty" `
2020-01-10 05:23:55 +00:00
// 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.
2020-01-09 15:27:00 +00:00
Selfie * PassportFile ` json:"selfie,omitempty" `
2020-01-10 05:23:55 +00:00
// 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.
2020-01-09 15:27:00 +00:00
Translation [ ] * PassportFile ` json:"translation,omitempty" `
// Base64-encoded element hash for using in PassportElementErrorUnspecified
Hash string ` json:"hash" `
}
2020-01-10 05:23:55 +00:00
// EncryptedCredentials contains data required for decrypting and authenticating EncryptedPassportElement. See the Telegram Passport Documentation for a complete description of the data decryption and authentication processes.
2020-01-09 15:27:00 +00:00
EncryptedCredentials struct {
2020-01-10 05:23:55 +00:00
// Base64-encoded encrypted JSON-serialized data with unique user's payload, data hashes and secrets required for EncryptedPassportElement decryption and authentication
2020-01-09 15:27:00 +00:00
Data string ` json:"data" `
// Base64-encoded data hash for data authentication
Hash string ` json:"hash" `
2020-01-10 05:23:55 +00:00
// Base64-encoded secret, encrypted with the bot's public RSA key, required for data decryption
2020-01-09 15:27:00 +00:00
Secret string ` json:"secret" `
}
2020-01-10 05:23:55 +00:00
// PassportElementError represents an error in the Telegram Passport element which was submitted that should be resolved by the user.
2020-01-09 15:27:00 +00:00
PassportElementError interface {
PassportElementErrorMessage ( ) string
PassportElementErrorSource ( ) string
PassportElementErrorType ( ) string
}
2020-01-10 05:23:55 +00:00
// PassportElementErrorDataField represents an issue in one of the data fields that was provided by the user. The error is considered resolved when the field's value changes.
2020-01-09 15:27:00 +00:00
PassportElementErrorDataField struct {
// Error source, must be data
Source string ` json:"source" `
2020-01-10 05:23:55 +00:00
// The section of the user's Telegram Passport which has the error, one of "personal_details", "passport", "driver_license", "identity_card", "internal_passport", "address"
2020-01-09 15:27:00 +00:00
Type string ` json:"type" `
// Name of the data field which has the error
FieldName string ` json:"field_name" `
// Base64-encoded data hash
DataHash string ` json:"data_hash" `
// Error message
Message string ` json:"message" `
}
2020-01-10 05:23:55 +00:00
// PassportElementErrorFrontSide represents an issue with the front side of a document. The error is considered resolved when the file with the front side of the document changes.
2020-01-09 15:27:00 +00:00
PassportElementErrorFrontSide struct {
// Error source, must be front_side
Source string ` json:"source" `
2020-01-10 05:23:55 +00:00
// The section of the user's Telegram Passport which has the issue, one of "passport", "driver_license", "identity_card", "internal_passport"
2020-01-09 15:27:00 +00:00
Type string ` json:"type" `
// Base64-encoded hash of the file with the front side of the document
FileHash string ` json:"file_hash" `
// Error message
Message string ` json:"message" `
}
2020-01-10 05:23:55 +00:00
// PassportElementErrorReverseSide represents an issue with the reverse side of a document. The error is considered resolved when the file with reverse side of the document changes.
2020-01-09 15:27:00 +00:00
PassportElementErrorReverseSide struct {
// Error source, must be reverse_side
Source string ` json:"source" `
2020-01-10 05:23:55 +00:00
// The section of the user's Telegram Passport which has the issue, one of "driver_license", "identity_card"
2020-01-09 15:27:00 +00:00
Type string ` json:"type" `
// Base64-encoded hash of the file with the reverse side of the document
FileHash string ` json:"file_hash" `
// Error message
Message string ` json:"message" `
}
2020-01-10 05:23:55 +00:00
// PassportElementErrorSelfie represents an issue with the selfie with a document. The error is considered resolved when the file with the selfie changes.
2020-01-09 15:27:00 +00:00
PassportElementErrorSelfie struct {
// Error source, must be selfie
Source string ` json:"source" `
2020-01-10 05:23:55 +00:00
// The section of the user's Telegram Passport which has the issue, one of "passport", "driver_license", "identity_card", "internal_passport"
2020-01-09 15:27:00 +00:00
Type string ` json:"type" `
// Base64-encoded hash of the file with the selfie
FileHash string ` json:"file_hash" `
// Error message
Message string ` json:"message" `
}
2020-01-10 05:23:55 +00:00
// PassportElementErrorFile represents an issue with a document scan. The error is considered resolved when the file with the document scan changes.
2020-01-09 15:27:00 +00:00
PassportElementErrorFile struct {
// Error source, must be file
Source string ` json:"source" `
2020-01-10 05:23:55 +00:00
// The section of the user's Telegram Passport which has the issue, one of "utility_bill", "bank_statement", "rental_agreement", "passport_registration", "temporary_registration"
2020-01-09 15:27:00 +00:00
Type string ` json:"type" `
// Base64-encoded file hash
FileHash string ` json:"file_hash" `
// Error message
Message string ` json:"message" `
}
2020-01-10 05:23:55 +00:00
// PassportElementErrorFiles represents an issue with a list of scans. The error is considered resolved when the list of files containing the scans changes.
2020-01-09 15:27:00 +00:00
PassportElementErrorFiles struct {
// Error source, must be files
Source string ` json:"source" `
2020-01-10 05:23:55 +00:00
// The section of the user's Telegram Passport which has the issue, one of "utility_bill", "bank_statement", "rental_agreement", "passport_registration", "temporary_registration"
2020-01-09 15:27:00 +00:00
Type string ` json:"type" `
// List of base64-encoded file hashes
FileHashes [ ] string ` json:"file_hashes" `
// Error message
Message string ` json:"message" `
}
2020-01-10 05:23:55 +00:00
// PassportElementErrorTranslationFile represents an issue with one of the files that constitute the translation of a document. The error is considered resolved when the file changes.
2020-01-09 15:27:00 +00:00
PassportElementErrorTranslationFile struct {
// Error source, must be translation_file
Source string ` json:"source" `
2020-01-10 05:23:55 +00:00
// Type of element of the user's Telegram Passport which has the issue, one of “passport”, “driver_license”, “identity_card”, “internal_passport”, “utility_bill”, “bank_statement”, “rental_agreement”, “passport_registration”, “temporary_registration”
2020-01-09 15:27:00 +00:00
Type string ` json:"type" `
// Base64-encoded file hash
FileHash string ` json:"file_hash" `
// Error message
Message string ` json:"message" `
}
2020-01-10 05:23:55 +00:00
// PassportElementErrorTranslationFiles represents an issue with the translated version of a document. The error is considered resolved when a file with the document translation change.
2020-01-09 15:27:00 +00:00
PassportElementErrorTranslationFiles struct {
// Error source, must be translation_files
Source string ` json:"source" `
2020-01-10 05:23:55 +00:00
// Type of element of the user's Telegram Passport which has the issue, one of “passport”, “driver_license”, “identity_card”, “internal_passport”, “utility_bill”, “bank_statement”, “rental_agreement”, “passport_registration”, “temporary_registration”
2020-01-09 15:27:00 +00:00
Type string ` json:"type" `
// List of base64-encoded file hashes
FileHashes [ ] string ` json:"file_hashes" `
// Error message
Message string ` json:"message" `
}
2020-01-10 05:23:55 +00:00
// PassportElementErrorUnspecified represents an issue in an unspecified place. The error is considered resolved when new data is added.
2020-01-09 15:27:00 +00:00
PassportElementErrorUnspecified struct {
// Error source, must be unspecified
Source string ` json:"source" `
// Type of element of the user's Telegram Passport which has the issue
Type string ` json:"type" `
// Base64-encoded element hash
ElementHash string ` json:"element_hash" `
// Error message
Message string ` json:"message" `
}
SetPassportDataErrors struct {
// User identifier
2021-03-09 14:15:28 +00:00
UserID int64 ` json:"user_id" `
2020-01-09 15:27:00 +00:00
// A JSON-serialized array describing the errors
Errors [ ] PassportElementError ` json:"errors" `
}
// AuthParameters represent a Telegram Passport auth parameters for SDK.
Auth struct {
2020-01-10 05:23:55 +00:00
// Unique identifier for the b. You can get it from bot token. For example, for the bot token 1234567:4TT8bAc8GHUspu3ERYn-KGcvsvGB9u_n4ddy, the bot id is 1234567.
2021-03-09 14:15:28 +00:00
BotID int64 ` json:"bot_id" `
2020-01-09 15:27:00 +00:00
2020-01-10 05:23:55 +00:00
// A JSON-serialized object describing the data you want to request
2020-01-09 15:27:00 +00:00
Scope * PassportScope ` json:"scope" `
// Public key of the bot
PublicKey string ` json:"public_key" `
// Bot-specified nonce.
//
2020-01-10 05:23:55 +00:00
// Important: For security purposes it should be a cryptographically secure unique identifier of the request. In particular, it should be long enough and it should be generated using a cryptographically secure pseudorandom number generator. You should never accept credentials with the same nonce twice.
2020-01-09 15:27:00 +00:00
Nonce string ` json:"nonce" `
}
// PassportScope represents the data to be requested.
PassportScope struct {
2020-01-10 05:23:55 +00:00
// List of requested elements, each type may be used only once in the entire array of PassportScopeElement objects
2020-01-09 15:27:00 +00:00
Data [ ] * PassportScopeElement ` json:"data" `
// Scope version, must be 1
V int ` json:"v" `
}
// PassportScopeElement represents a requested element.
PassportScopeElement interface {
PassportScopeElementTranslation ( ) bool
PassportScopeElementSelfie ( ) bool
}
// PassportScopeElementOneOfSeveral represents several elements one of which must be provided.
PassportScopeElementOneOfSeveral struct {
// List of elements one of which must be provided;
OneOf [ ] * PassportScopeElementOne ` json:"one_of" `
2020-01-10 05:23:55 +00:00
// Use this parameter if you want to request a selfie with the document from this list that the user chooses to upload.
2020-01-09 15:27:00 +00:00
Selfie bool ` json:"selfie,omitempty" `
2020-01-10 05:23:55 +00:00
// Use this parameter if you want to request a translation of the document from this list that the user chooses to upload. Note: We suggest to only request translations after you have received a valid document that requires one.
2020-01-09 15:27:00 +00:00
Translation bool ` json:"translation,omitempty" `
}
2020-01-10 05:23:55 +00:00
// PassportScopeElementOne represents one particular element that must be provided. If no options are needed, String can be used instead of this object to specify the type of the element.
2020-01-09 15:27:00 +00:00
PassportScopeElementOne struct {
// Element type.
Type string ` json:"type" `
2020-01-10 05:23:55 +00:00
// Use this parameter if you want to request a selfie with the document as well.
2020-01-09 15:27:00 +00:00
Selfie bool ` json:"selfie,omitempty" `
2020-01-10 05:23:55 +00:00
// Use this parameter if you want to request a translation of the document as well.
2020-01-09 15:27:00 +00:00
Translation bool ` json:"translation,omitempty" `
2020-01-10 05:23:55 +00:00
// Use this parameter to request the first, last and middle name of the user in the language of the user's country of residence.
2020-01-09 15:27:00 +00:00
NativeNames bool ` json:"native_names,omitempty" `
}
Passport struct {
// Personal Details
PersonalDetails struct {
Data * PersonalDetails ` json:"data" `
} ` json:"personal_details" `
// Passport
Passport struct {
Data * IDDocumentData ` json:"data" `
FrontSide * PassportFile ` json:"front_side" `
Selfie * PassportFile ` json:"selfie,omitempty" `
Translation [ ] * PassportFile ` json:"translation,omitempty" `
} ` json:"passport" `
// Internal Passport
InternalPassport struct {
Data * IDDocumentData ` json:"data" `
FrontSide * PassportFile ` json:"front_side" `
Selfie * PassportFile ` json:"selfie,omitempty" `
Translation [ ] * PassportFile ` json:"translation,omitempty" `
} ` json:"internal_passport" `
// Driver License
DriverLicense struct {
Data * IDDocumentData ` json:"data" `
FrontSide * PassportFile ` json:"front_side" `
ReverseSide * PassportFile ` json:"reverse_side" `
Selfie * PassportFile ` json:"selfie,omitempty" `
Translation [ ] * PassportFile ` json:"translation,omitempty" `
} ` json:"driver_license" `
// Identity Card
IdentityCard struct {
Data * IDDocumentData ` json:"data" `
FrontSide * PassportFile ` json:"front_side" `
ReverseSide * PassportFile ` json:"reverse_side" `
Selfie * PassportFile ` json:"selfie,omitempty" `
Translation [ ] * PassportFile ` json:"translation,omitempty" `
} ` json:"identity_card" `
// Address
Address struct {
Data * ResidentialAddress ` json:"data" `
} ` json:"address" `
// Utility Bill
UtilityBill struct {
Files [ ] * PassportFile ` json:"files" `
Translation [ ] * PassportFile ` json:"translation,omitempty" `
} ` json:"utility_bill" `
// Bank Statement
BankStatement struct {
Files [ ] * PassportFile ` json:"files" `
Translation [ ] * PassportFile ` json:"translation,omitempty" `
} ` json:"bank_statement" `
// Rental Agreement
RentalAgreement struct {
Files [ ] * PassportFile ` json:"files" `
Translation [ ] * PassportFile ` json:"translation,omitempty" `
} ` json:"rental_agreement" `
// Registration Page in the Internal Passport
PassportRegistration struct {
Files [ ] * PassportFile ` json:"files" `
Translation [ ] * PassportFile ` json:"translation,omitempty" `
} ` json:"passport_registration" `
// Temporary Registration
TemporaryRegistration struct {
Files [ ] * PassportFile ` json:"files" `
Translation [ ] * PassportFile ` json:"translation,omitempty" `
} ` json:"temporary_registration" `
// Phone number
PhoneNumber string ` json:"phone_number" `
// Email
Email string ` json:"email" `
}
// PersonalDetails represents personal details.
PersonalDetails struct {
// First Name
FirstName string ` json:"first_name" `
// Last Name
LastName string ` json:"last_name" `
// Middle Name
MiddleName string ` json:"middle_name,omitempty" `
// Date of birth in DD.MM.YYYY format
BirthDate string ` json:"birth_date" `
// Gender, male or female
Gender string ` json:"gender" `
// Citizenship (ISO 3166-1 alpha-2 country code)
CountryCode string ` json:"country_code" `
// Country of residence (ISO 3166-1 alpha-2 country code)
ResidenceCountryCode string ` json:"residence_country_code" `
// First Name in the language of the user's country of residence
FirstNameNative string ` json:"first_name_native" `
// Last Name in the language of the user's country of residence
LastNameNative string ` json:"last_name_native" `
// Middle Name in the language of the user's country of residence
MiddleNameNative string ` json:"middle_name_native,omitempty" `
}
// ResidentialAddress represents a residential address.
ResidentialAddress struct {
// First line for the address
StreetLine1 string ` json:"street_line1" `
// Second line for the address
StreetLine2 string ` json:"street_line2,omitempty" `
// City
City string ` json:"city" `
// State
State string ` json:"state,omitempty" `
// ISO 3166-1 alpha-2 country code
CountryCode string ` json:"country_code" `
// Address post code
PostCode string ` json:"post_code" `
}
// IDDocumentData represents the data of an identity document.
IDDocumentData struct {
// Document number
DocumentNo string ` json:"document_no" `
// Date of expiry, in DD.MM.YYYY format
ExpiryDate string ` json:"expiry_date,omitempty" `
}
// Credentials is a JSON-serialized object.
Credentials struct {
// Credentials for encrypted data
SecureData * SecureData ` json:"secure_data" `
// Bot-specified nonce
Nonce string ` json:"nonce" `
}
2020-01-10 05:23:55 +00:00
// SecureData represents the credentials required to decrypt encrypted data. All fields are optional and depend on fields that were requested.
2020-01-09 15:27:00 +00:00
SecureData struct {
// Credentials for encrypted personal details
PersonalDetails * SecureValue ` json:"personal_details,omitempty" `
// Credentials for encrypted passport
Passport * SecureValue ` json:"passport,omitempty" `
// Credentials for encrypted internal passport
InternalPassport * SecureValue ` json:"internal_passport,omitempty" `
// Credentials for encrypted driver license
DriverLicense * SecureValue ` json:"driver_license,omitempty" `
// Credentials for encrypted ID card
IdentityCard * SecureValue ` json:"identity_card,omitempty" `
// Credentials for encrypted residential address
Address * SecureValue ` json:"address,omitempty" `
// Credentials for encrypted utility bill
UtilityBill * SecureValue ` json:"utility_bill,omitempty" `
// Credentials for encrypted bank statement
BankStatement * SecureValue ` json:"bank_statement,omitempty" `
// Credentials for encrypted rental agreement
RentalAgreement * SecureValue ` json:"rental_agreement,omitempty" `
// Credentials for encrypted registration from internal passport
PassportRegistration * SecureValue ` json:"passport_registration,omitempty" `
// Credentials for encrypted temporary registration
TemporaryRegistration * SecureValue ` json:"temporary_registration,omitempty" `
}
2020-01-10 05:23:55 +00:00
// SecureValue represents the credentials required to decrypt encrypted values. All fields are optional and depend on the type of fields that were requested.
2020-01-09 15:27:00 +00:00
SecureValue struct {
// Credentials for encrypted Telegram Passport data.
Data * DataCredentials ` json:"data,omitempty" `
// Credentials for an encrypted document's front side.
FrontSide * FileCredentials ` json:"front_side,omitempty" `
// Credentials for an encrypted document's reverse side.
ReverseSide * FileCredentials ` json:"reverse_side,omitempty" `
// Credentials for an encrypted selfie of the user with a document.
Selfie * FileCredentials ` json:"selfie,omitempty" `
// Credentials for an encrypted translation of the document.
Translation [ ] * FileCredentials ` json:"translation,omitempty" `
// Credentials for encrypted files.
Files [ ] * FileCredentials ` json:"files,omitempty" `
}
2020-01-10 05:23:55 +00:00
// DataCredentials can be used to decrypt encrypted data from the data field in EncryptedPassportElement.
2020-01-09 15:27:00 +00:00
DataCredentials struct {
// Checksum of encrypted data
DataHash string ` json:"data_hash" `
// Secret of encrypted data
Secret string ` json:"secret" `
}
2020-01-10 05:23:55 +00:00
// FileCredentials can be used to decrypt encrypted files from the front_side, reverse_side, selfie, files and translation fields in EncryptedPassportElement.
2020-01-09 15:27:00 +00:00
FileCredentials struct {
// Checksum of encrypted file
FileHash string ` json:"file_hash" `
// Secret of encrypted file
Secret string ` json:"secret" `
}
)
var ErrNotEqual = errors . New ( "credentials hash and credentials data hash is not equal" )
2020-01-10 05:23:55 +00:00
// SetPassportDataErrors informs a user that some of the Telegram Passport elements they provided contains errors. The user will not be able to re-submit their Passport to you until the errors are fixed (the contents of the field for which you returned the error must change). Returns True on success.
2020-01-09 15:27:00 +00:00
//
2020-01-10 05:23:55 +00:00
// Use this if the data submitted by the user doesn't satisfy the standards your service requires for any reason. For example, if a birthday date seems invalid, a submitted document is blurry, a scan shows evidence of tampering, etc. Supply some details in the error message to make sure the user knows how to correct the issues.
2021-03-09 14:15:28 +00:00
func ( b Bot ) SetPassportDataErrors ( uid int64 , errors ... PassportElementError ) ( ok bool , err error ) {
2020-01-09 15:27:00 +00:00
src , err := b . Do ( MethodSetPassportDataErrors , SetPassportDataErrors {
UserID : uid , Errors : errors ,
} )
if err != nil {
2020-06-05 21:57:29 +00:00
return ok , err
2020-01-09 15:27:00 +00:00
}
2020-06-05 21:57:29 +00:00
if err = parseResponseError ( b . marshler , src , & ok ) ; err != nil {
return
2020-01-09 15:27:00 +00:00
}
2020-06-05 21:57:29 +00:00
return
2020-01-09 15:27:00 +00:00
}
/ * TODO ( toby3d )
func ( b * Bot ) DecryptFile ( pf * PassportFile , fc * FileCredentials ) ( data [ ] byte , err error ) {
secret , err := decodeField ( fc . Secret )
if err != nil {
return nil , err
}
hash , err := decodeField ( fc . FileHash )
if err != nil {
return nil , err
}
key , iv := decryptSecretHash ( secret , hash )
file , err := b . GetFile ( pf . FileID )
if err != nil {
return nil , err
}
if _ , data , err = b . Client . Get ( nil , b . NewFileURL ( file . FilePath ) . String ( ) ) ; err != nil {
return nil , err
}
if data , err = decryptData ( key , iv , data ) ; err != nil {
return nil , err
}
if ! match ( hash , data ) {
err = ErrNotEqual
return nil , err
}
offset := int ( data [ 0 ] )
data = data [ offset : ]
return data , nil
}
func ( dc * DataCredentials ) decrypt ( d string ) ( data [ ] byte , err error ) {
secret , err := decodeField ( dc . Secret )
if err != nil {
return
}
hash , err := decodeField ( dc . DataHash )
if err != nil {
return
}
key , iv := decryptSecretHash ( secret , hash )
if data , err = decodeField ( d ) ; err != nil {
return
}
if data , err = decryptData ( key , iv , data ) ; err != nil {
return
}
if ! match ( hash , data ) {
err = ErrNotEqual
}
offset := int ( data [ 0 ] )
data = data [ offset : ]
return
}
func ( ec * EncryptedCredentials ) Decrypt ( pk * rsa . PrivateKey ) ( * Credentials , error ) {
if ec == nil || pk == nil {
return nil , nil
}
data , err := decrypt ( pk , ec . Secret , ec . Hash , ec . Data )
if err != nil {
return nil , err
}
var c Credentials
if err = json . ConfigFastest . Unmarshal ( data , & c ) ; err != nil {
return nil , Error { Description : err . Error ( ) }
}
return & c , err
}
func ( epe * EncryptedPassportElement ) DecryptPersonalDetails ( sv * SecureValue ) ( * PersonalDetails , error ) {
if ! epe . IsPersonalDetails ( ) || ! sv . HasData ( ) {
return nil , nil
}
body , err := sv . Data . decrypt ( epe . Data )
if err != nil {
return nil , err
}
var pd PersonalDetails
if err = json . ConfigFastest . Unmarshal ( body , & pd ) ; err != nil {
return nil , Error { Description : err . Error ( ) }
}
return & pd , err
}
func ( epe * EncryptedPassportElement ) DecryptPassport ( sv * SecureValue , b * Bot ) ( * IDDocumentData , [ ] byte , [ ] byte , [ ] [ ] byte , error ) {
if ! epe . IsPassport ( ) || ! sv . HasData ( ) || ! sv . HasFrontSide ( ) {
return nil , nil , nil , nil , nil
}
body , err := sv . Data . decrypt ( epe . Data )
if err != nil {
return nil , nil , nil , nil , err
}
var idd IDDocumentData
if err = b . marshler . Unmarshal ( body , & idd ) ; err != nil {
return nil , nil , nil , nil , err
}
fs , err := b . DecryptFile ( epe . FrontSide , sv . FrontSide )
if err != nil {
return & idd , nil , nil , nil , err
}
var s [ ] byte
if sv . HasSelfie ( ) {
if s , err = b . DecryptFile ( epe . Selfie , sv . Selfie ) ; err != nil {
return & idd , fs , nil , nil , err
}
}
t := make ( [ ] [ ] byte , len ( sv . Translation ) )
if sv . HasTranslation ( ) {
for i := range t {
if t [ i ] , err = b . DecryptFile ( epe . Translation [ i ] , sv . Translation [ i ] ) ; err != nil {
return & idd , fs , s , nil , err
}
}
}
return & idd , fs , s , t , nil
}
func ( epe * EncryptedPassportElement ) DecryptInternalPassport ( sv * SecureValue , b * Bot ) ( * IDDocumentData , [ ] byte , [ ] byte , [ ] [ ] byte , error ) {
if ! epe . IsInternalPassport ( ) || ! sv . HasData ( ) || ! sv . HasFrontSide ( ) {
return nil , nil , nil , nil , nil
}
body , err := sv . Data . decrypt ( epe . Data )
if err != nil {
return nil , nil , nil , nil , err
}
var idd IDDocumentData
if err = b . marshler . Unmarshal ( body , & idd ) ; err != nil {
return nil , nil , nil , nil , err
}
fs , err := b . DecryptFile ( epe . FrontSide , sv . FrontSide )
if err != nil {
return & idd , nil , nil , nil , err
}
var s [ ] byte
if sv . HasSelfie ( ) {
if s , err = b . DecryptFile ( epe . Selfie , sv . Selfie ) ; err != nil {
return & idd , fs , nil , nil , err
}
}
t := make ( [ ] [ ] byte , len ( sv . Translation ) )
if sv . HasTranslation ( ) {
for i := range t {
if t [ i ] , err = b . DecryptFile ( epe . Translation [ i ] , sv . Translation [ i ] ) ; err != nil {
return & idd , fs , s , nil , err
}
}
}
return & idd , fs , s , t , nil
}
func ( epe * EncryptedPassportElement ) DecryptDriverLicense ( sv * SecureValue , b * Bot ) ( * IDDocumentData , [ ] byte , [ ] byte , [ ] byte , [ ] [ ] byte , error ) {
if ! epe . IsDriverLicense ( ) || ! sv . HasData ( ) || ! sv . HasFrontSide ( ) || ! sv . HasReverseSide ( ) {
return nil , nil , nil , nil , nil , nil
}
body , err := sv . Data . decrypt ( epe . Data )
if err != nil {
return nil , nil , nil , nil , nil , err
}
var idd IDDocumentData
if err = b . marshler . Unmarshal ( body , & idd ) ; err != nil {
return nil , nil , nil , nil , nil , err
}
fs , err := b . DecryptFile ( epe . FrontSide , sv . FrontSide )
if err != nil {
return & idd , nil , nil , nil , nil , err
}
rs , err := b . DecryptFile ( epe . ReverseSide , sv . ReverseSide )
if err != nil {
return & idd , nil , nil , nil , nil , err
}
var s [ ] byte
if sv . HasSelfie ( ) {
if s , err = b . DecryptFile ( epe . Selfie , sv . Selfie ) ; err != nil {
return & idd , fs , rs , nil , nil , err
}
}
t := make ( [ ] [ ] byte , len ( sv . Translation ) )
if sv . HasTranslation ( ) {
for i := range t {
if t [ i ] , err = b . DecryptFile ( epe . Translation [ i ] , sv . Translation [ i ] ) ; err != nil {
return & idd , fs , rs , s , nil , err
}
}
}
return & idd , fs , rs , s , t , nil
}
func ( epe * EncryptedPassportElement ) IsAddress ( ) bool {
return epe != nil && strings . EqualFold ( epe . Type , TypeAddress )
}
func ( epe * EncryptedPassportElement ) IsBankStatement ( ) bool {
return epe != nil && strings . EqualFold ( epe . Type , TypeBankStatement )
}
func ( epe * EncryptedPassportElement ) IsDriverLicense ( ) bool {
return epe != nil && strings . EqualFold ( epe . Type , TypeDriverLicense )
}
func ( epe * EncryptedPassportElement ) IsEmail ( ) bool {
return epe != nil && strings . EqualFold ( epe . Type , TypeEmail )
}
func ( epe * EncryptedPassportElement ) IsIdentityCard ( ) bool {
return epe != nil && strings . EqualFold ( epe . Type , TypeIdentityCard )
}
func ( epe * EncryptedPassportElement ) IsInternalPassport ( ) bool {
return epe != nil && strings . EqualFold ( epe . Type , TypeInternalPassport )
}
func ( epe * EncryptedPassportElement ) IsPassport ( ) bool {
return epe != nil && strings . EqualFold ( epe . Type , TypePassport )
}
func ( epe * EncryptedPassportElement ) IsPassportRegistration ( ) bool {
return epe != nil && strings . EqualFold ( epe . Type , TypePassportRegistration )
}
func ( epe * EncryptedPassportElement ) IsPersonalDetails ( ) bool {
return epe != nil && strings . EqualFold ( epe . Type , TypePersonalDetails )
}
func ( epe * EncryptedPassportElement ) IsPhoneNumber ( ) bool {
return epe != nil && strings . EqualFold ( epe . Type , TypePhoneNumber )
}
func ( epe * EncryptedPassportElement ) IsRentalAgreement ( ) bool {
return epe != nil && strings . EqualFold ( epe . Type , TypeRentalAgreement )
}
func ( epe * EncryptedPassportElement ) IsTemporaryRegistration ( ) bool {
return epe != nil && strings . EqualFold ( epe . Type , TypeTemporaryRegistration )
}
func ( epe * EncryptedPassportElement ) IsUtilityBill ( ) bool {
return epe != nil && strings . EqualFold ( epe . Type , TypeUtilityBill )
}
func ( idd * IDDocumentData ) ExpiryTime ( ) * time . Time {
if idd == nil || idd . ExpiryDate == "" {
return nil
}
et , err := time . Parse ( "02.01.2006" , idd . ExpiryDate )
if err != nil {
return nil
}
return & et
}
func decrypt ( pk * rsa . PrivateKey , s , h , d string ) ( obj [ ] byte , err error ) {
// Note that all base64-encoded fields should be decoded before use.
secret , err := decodeField ( s )
if err != nil {
return nil , err
}
hash , err := decodeField ( h )
if err != nil {
return nil , err
}
data , err := decodeField ( d )
if err != nil {
return nil , err
}
if pk != nil {
// Decrypt the credentials secret (secret field in EncryptedCredentials)
// using your private key
if secret , err = decryptSecret ( pk , secret ) ; err != nil {
return nil , err
}
}
// Use this secret and the credentials hash (hash field in
// EncryptedCredentials) to calculate credentials_key and credentials_iv
key , iv := decryptSecretHash ( secret , hash )
// Decrypt the credentials data (data field in EncryptedCredentials) by
// AES256-CBC using these credentials_key and credentials_iv.
if data , err = decryptData ( key , iv , data ) ; err != nil {
return nil , err
}
// IMPORTANT: At this step, make sure that the credentials hash is equal
// to SHA256(credentials_data)
if ! match ( hash , data ) {
return nil , ErrNotEqual
}
// Credentials data is padded with 32 to 255 random padding bytes to make
// its length divisible by 16 bytes. The first byte contains the length
// of this padding (including this byte). Remove the padding to get the
// data.
return data [ int ( data [ 0 ] ) : ] , nil
}
func decodeField ( rawField string ) ( field [ ] byte , err error ) {
return base64 . StdEncoding . DecodeString ( rawField )
}
func decryptSecret ( pk * rsa . PrivateKey , s [ ] byte ) ( secret [ ] byte , err error ) {
return rsa . DecryptOAEP ( sha1 . New ( ) , rand . Reader , pk , s , nil ) //nolint: gosec
}
func decryptSecretHash ( s , h [ ] byte ) ( key , iv [ ] byte ) {
var err error
hash := sha512 . New ( )
if _ , err = hash . Write ( s ) ; err != nil {
return
}
if _ , err = hash . Write ( h ) ; err != nil {
return
}
sh := hash . Sum ( nil )
return sh [ 0 : 32 ] , sh [ 32 : 32 + 16 ]
}
func match ( h , d [ ] byte ) bool {
dh := sha256 . New ( )
if _ , err := dh . Write ( d ) ; err != nil {
return false
}
return bytes . EqualFold ( h , dh . Sum ( nil ) )
}
func decryptData ( key , iv , data [ ] byte ) ( buf [ ] byte , err error ) {
block , err := aes . NewCipher ( key )
if err != nil {
return
}
buf = make ( [ ] byte , len ( data ) )
cipher . NewCBCDecrypter ( block , iv ) . CryptBlocks ( buf , data )
return
}
func ( pd * PersonalDetails ) BirthTime ( ) * time . Time {
if pd == nil || pd . BirthDate == "" {
return nil
}
bt , err := time . Parse ( "02.01.2006" , pd . BirthDate )
if err != nil {
return nil
}
return & bt
}
func ( pd PersonalDetails ) FullName ( ) string { return pd . FirstName + " " + pd . LastName }
func ( pd PersonalDetails ) FullNameNative ( ) string { return pd . FirstNameNative + " " + pd . LastNameNative }
func ( sv * SecureValue ) HasData ( ) bool { return sv != nil && sv . Data != nil }
func ( sv * SecureValue ) HasFiles ( ) bool { return sv != nil && len ( sv . Files ) > 0 }
func ( sv * SecureValue ) HasFrontSide ( ) bool { return sv != nil && sv . FrontSide != nil }
func ( sv * SecureValue ) HasReverseSide ( ) bool { return sv != nil && sv . ReverseSide != nil }
func ( sv * SecureValue ) HasSelfie ( ) bool { return sv != nil && sv . Selfie != nil }
func ( sv * SecureValue ) HasTranslation ( ) bool { return sv != nil && len ( sv . Translation ) > 0 }
* /