1
0
Fork 0
telegram/passport.go

969 lines
31 KiB
Go

package telegram
import "errors"
/*
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/rsa"
"crypto/sha1" //nolint: gosec
"crypto/sha256"
"crypto/sha512"
"encoding/base64"
*/
type (
// PassportData contains information about Telegram Passport data shared with the bot by the user.
PassportData struct {
// Array with information about documents and other Telegram Passport elements that was shared with the bot
Data []*EncryptedPassportElement `json:"data"`
// Encrypted credentials required to decrypt the data
Credentials *EncryptedCredentials `json:"credentials"`
}
// PassportFile represents a file uploaded to Telegram Passport. Currently all Telegram Passport files are in JPEG format when decrypted and don't exceed 10MB.
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"`
}
// EncryptedPassportElement contains information about documents or other Telegram Passport elements shared with the bot by the user.
EncryptedPassportElement struct {
// Element type.
Type string `json:"type"`
// 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.
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"`
// 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 []*PassportFile `json:"files,omitempty"`
// 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.
FrontSide *PassportFile `json:"front_side,omitempty"`
// 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.
ReverseSide *PassportFile `json:"reverse_side,omitempty"`
// 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 `json:"selfie,omitempty"`
// 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 []*PassportFile `json:"translation,omitempty"`
// Base64-encoded element hash for using in PassportElementErrorUnspecified
Hash string `json:"hash"`
}
// 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.
EncryptedCredentials struct {
// Base64-encoded encrypted JSON-serialized data with unique user's payload, data hashes and secrets required for EncryptedPassportElement decryption and authentication
Data string `json:"data"`
// Base64-encoded data hash for data authentication
Hash string `json:"hash"`
// Base64-encoded secret, encrypted with the bot's public RSA key, required for data decryption
Secret string `json:"secret"`
}
// PassportElementError represents an error in the Telegram Passport element which was submitted that should be resolved by the user.
PassportElementError interface {
PassportElementErrorMessage() string
PassportElementErrorSource() string
PassportElementErrorType() string
}
// 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.
PassportElementErrorDataField struct {
// Error source, must be data
Source string `json:"source"`
// The section of the user's Telegram Passport which has the error, one of "personal_details", "passport", "driver_license", "identity_card", "internal_passport", "address"
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"`
}
// 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.
PassportElementErrorFrontSide struct {
// Error source, must be front_side
Source string `json:"source"`
// The section of the user's Telegram Passport which has the issue, one of "passport", "driver_license", "identity_card", "internal_passport"
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"`
}
// 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.
PassportElementErrorReverseSide struct {
// Error source, must be reverse_side
Source string `json:"source"`
// The section of the user's Telegram Passport which has the issue, one of "driver_license", "identity_card"
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"`
}
// PassportElementErrorSelfie represents an issue with the selfie with a document. The error is considered resolved when the file with the selfie changes.
PassportElementErrorSelfie struct {
// Error source, must be selfie
Source string `json:"source"`
// The section of the user's Telegram Passport which has the issue, one of "passport", "driver_license", "identity_card", "internal_passport"
Type string `json:"type"`
// Base64-encoded hash of the file with the selfie
FileHash string `json:"file_hash"`
// Error message
Message string `json:"message"`
}
// PassportElementErrorFile represents an issue with a document scan. The error is considered resolved when the file with the document scan changes.
PassportElementErrorFile struct {
// Error source, must be file
Source string `json:"source"`
// The section of the user's Telegram Passport which has the issue, one of "utility_bill", "bank_statement", "rental_agreement", "passport_registration", "temporary_registration"
Type string `json:"type"`
// Base64-encoded file hash
FileHash string `json:"file_hash"`
// Error message
Message string `json:"message"`
}
// PassportElementErrorFiles represents an issue with a list of scans. The error is considered resolved when the list of files containing the scans changes.
PassportElementErrorFiles struct {
// Error source, must be files
Source string `json:"source"`
// The section of the user's Telegram Passport which has the issue, one of "utility_bill", "bank_statement", "rental_agreement", "passport_registration", "temporary_registration"
Type string `json:"type"`
// List of base64-encoded file hashes
FileHashes []string `json:"file_hashes"`
// Error message
Message string `json:"message"`
}
// 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.
PassportElementErrorTranslationFile struct {
// Error source, must be translation_file
Source string `json:"source"`
// 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”
Type string `json:"type"`
// Base64-encoded file hash
FileHash string `json:"file_hash"`
// Error message
Message string `json:"message"`
}
// PassportElementErrorTranslationFiles represents an issue with the translated version of a document. The error is considered resolved when a file with the document translation change.
PassportElementErrorTranslationFiles struct {
// Error source, must be translation_files
Source string `json:"source"`
// 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”
Type string `json:"type"`
// List of base64-encoded file hashes
FileHashes []string `json:"file_hashes"`
// Error message
Message string `json:"message"`
}
// PassportElementErrorUnspecified represents an issue in an unspecified place. The error is considered resolved when new data is added.
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
UserID int64 `json:"user_id"`
// A JSON-serialized array describing the errors
Errors []PassportElementError `json:"errors"`
}
// AuthParameters represent a Telegram Passport auth parameters for SDK.
Auth struct {
// 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.
BotID int64 `json:"bot_id"`
// A JSON-serialized object describing the data you want to request
Scope *PassportScope `json:"scope"`
// Public key of the bot
PublicKey string `json:"public_key"`
// Bot-specified nonce.
//
// 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.
Nonce string `json:"nonce"`
}
// PassportScope represents the data to be requested.
PassportScope struct {
// List of requested elements, each type may be used only once in the entire array of PassportScopeElement objects
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"`
// Use this parameter if you want to request a selfie with the document from this list that the user chooses to upload.
Selfie bool `json:"selfie,omitempty"`
// 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.
Translation bool `json:"translation,omitempty"`
}
// 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.
PassportScopeElementOne struct {
// Element type.
Type string `json:"type"`
// Use this parameter if you want to request a selfie with the document as well.
Selfie bool `json:"selfie,omitempty"`
// Use this parameter if you want to request a translation of the document as well.
Translation bool `json:"translation,omitempty"`
// Use this parameter to request the first, last and middle name of the user in the language of the user's country of residence.
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"`
}
// SecureData represents the credentials required to decrypt encrypted data. All fields are optional and depend on fields that were requested.
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"`
}
// SecureValue represents the credentials required to decrypt encrypted values. All fields are optional and depend on the type of fields that were requested.
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"`
}
// DataCredentials can be used to decrypt encrypted data from the data field in EncryptedPassportElement.
DataCredentials struct {
// Checksum of encrypted data
DataHash string `json:"data_hash"`
// Secret of encrypted data
Secret string `json:"secret"`
}
// FileCredentials can be used to decrypt encrypted files from the front_side, reverse_side, selfie, files and translation fields in EncryptedPassportElement.
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")
// 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.
//
// 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.
func (b Bot) SetPassportDataErrors(uid int64, errors ...PassportElementError) (ok bool, err error) {
src, err := b.Do(MethodSetPassportDataErrors, SetPassportDataErrors{
UserID: uid, Errors: errors,
})
if err != nil {
return ok, err
}
if err = parseResponseError(b.marshler, src, &ok); err != nil {
return
}
return
}
/* 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 }
*/