🔀 Merge branch 'feature/passport' into develop
This commit is contained in:
commit
f9c11ddc83
|
@ -1,6 +1,229 @@
|
|||
package telegram
|
||||
|
||||
type (
|
||||
// AuthParameters represent a Telegram Passport auth parameters for SDK.
|
||||
AuthParameters struct {
|
||||
// Unique identifier for the bot. You can get it from bot token.
|
||||
// For example, for the bot token
|
||||
// 1234567:4TT8bAc8GHUspu3ERYn-KGcvsvGB9u_n4ddy, the bot id is
|
||||
// 1234567.
|
||||
BotID int `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"`
|
||||
}
|
||||
|
||||
// PassportData contains information about Telegram Passport data shared with
|
||||
// the bot by the user.
|
||||
PassportData struct {
|
||||
|
@ -26,6 +249,96 @@ type (
|
|||
FileDate int64 `json:"file_date"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// EncryptedPassportElement contains information about documents or other
|
||||
// Telegram Passport elements shared with the bot by the user.
|
||||
EncryptedPassportElement struct {
|
||||
|
@ -67,6 +380,18 @@ type (
|
|||
// "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
|
||||
|
@ -89,7 +414,11 @@ type (
|
|||
|
||||
// PassportElementError represents an error in the Telegram Passport element
|
||||
// which was submitted that should be resolved by the user.
|
||||
PassportElementError interface{}
|
||||
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
|
||||
|
|
38
utils_bot.go
38
utils_bot.go
|
@ -165,3 +165,41 @@ func (b *Bot) NewRedirectURL(param string, group bool) *http.URI {
|
|||
|
||||
return link
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
_, data, err = b.Client.Get(nil, b.NewFileURL(file.FilePath).String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, err = decryptData(key, iv, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !match(hash, data) {
|
||||
err = ErrNotEqual
|
||||
return nil, err
|
||||
}
|
||||
|
||||
offset := int(data[0])
|
||||
data = data[offset:]
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package telegram
|
||||
|
||||
import "errors"
|
||||
|
||||
var ErrNotEqual = errors.New("credentials hash and credentials data hash is not equal")
|
||||
|
||||
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 err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data, err = decodeField(d)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
data, err = decryptData(key, iv, data)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !match(hash, data) {
|
||||
err = ErrNotEqual
|
||||
}
|
||||
|
||||
offset := int(data[0])
|
||||
data = data[offset:]
|
||||
|
||||
return
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package telegram
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
|
||||
json "github.com/pquerna/ffjson/ffjson"
|
||||
)
|
||||
|
||||
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
|
||||
err = json.Unmarshal(data, &c)
|
||||
return &c, err
|
||||
}
|
|
@ -0,0 +1,196 @@
|
|||
package telegram
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
json "github.com/pquerna/ffjson/ffjson"
|
||||
)
|
||||
|
||||
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
|
||||
err = json.Unmarshal(body, &pd)
|
||||
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 = json.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 = json.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 = json.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)
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package telegram
|
||||
|
||||
import "time"
|
||||
|
||||
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
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package telegram
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"encoding/base64"
|
||||
)
|
||||
|
||||
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
|
||||
secret, err = decryptSecret(pk, secret)
|
||||
if 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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Decrypt the credentials data (data field in EncryptedCredentials) by
|
||||
// AES256-CBC using these credentials_key and credentials_iv.
|
||||
data, err = decryptData(key, iv, data)
|
||||
if 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.
|
||||
offset := int(data[0])
|
||||
return data[offset:], 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)
|
||||
}
|
||||
|
||||
func decryptSecretHash(s, h []byte) (key, iv []byte) {
|
||||
hash := sha512.New()
|
||||
hash.Write(s)
|
||||
hash.Write(h)
|
||||
sh := hash.Sum(nil)
|
||||
|
||||
return sh[0:32], sh[32 : 32+16]
|
||||
}
|
||||
|
||||
func match(h, d []byte) bool {
|
||||
dh := sha256.New()
|
||||
dh.Write(d)
|
||||
|
||||
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
|
||||
}
|
|
@ -0,0 +1,217 @@
|
|||
package telegram
|
||||
|
||||
func (peedf *PassportElementErrorDataField) PassportElementErrorMessage() string {
|
||||
if peedf == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return peedf.Message
|
||||
}
|
||||
|
||||
func (peedf *PassportElementErrorDataField) PassportElementErrorSource() string {
|
||||
if peedf == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return peedf.Source
|
||||
}
|
||||
|
||||
func (peedf *PassportElementErrorDataField) PassportElementErrorType() string {
|
||||
if peedf == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return peedf.Type
|
||||
}
|
||||
|
||||
func (peeff *PassportElementErrorFrontSide) PassportElementErrorMessage() string {
|
||||
if peeff == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return peeff.Message
|
||||
}
|
||||
|
||||
func (peeff *PassportElementErrorFrontSide) PassportElementErrorSource() string {
|
||||
if peeff == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return peeff.Source
|
||||
}
|
||||
|
||||
func (peeff *PassportElementErrorFrontSide) PassportElementErrorType() string {
|
||||
if peeff == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return peeff.Type
|
||||
}
|
||||
|
||||
func (peerf *PassportElementErrorReverseSide) PassportElementErrorMessage() string {
|
||||
if peerf == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return peerf.Message
|
||||
}
|
||||
|
||||
func (peerf *PassportElementErrorReverseSide) PassportElementErrorSource() string {
|
||||
if peerf == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return peerf.Source
|
||||
}
|
||||
|
||||
func (peerf *PassportElementErrorReverseSide) PassportElementErrorType() string {
|
||||
if peerf == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return peerf.Type
|
||||
}
|
||||
|
||||
func (pees *PassportElementErrorSelfie) PassportElementErrorMessage() string {
|
||||
if pees == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return pees.Message
|
||||
}
|
||||
|
||||
func (pees *PassportElementErrorSelfie) PassportElementErrorSource() string {
|
||||
if pees == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return pees.Source
|
||||
}
|
||||
|
||||
func (pees *PassportElementErrorSelfie) PassportElementErrorType() string {
|
||||
if pees == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return pees.Type
|
||||
}
|
||||
|
||||
func (peef *PassportElementErrorFile) PassportElementErrorMessage() string {
|
||||
if peef == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return peef.Message
|
||||
}
|
||||
|
||||
func (peef *PassportElementErrorFile) PassportElementErrorSource() string {
|
||||
if peef == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return peef.Source
|
||||
}
|
||||
|
||||
func (peef *PassportElementErrorFile) PassportElementErrorType() string {
|
||||
if peef == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return peef.Type
|
||||
}
|
||||
|
||||
func (peef *PassportElementErrorFiles) PassportElementErrorMessage() string {
|
||||
if peef == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return peef.Message
|
||||
}
|
||||
|
||||
func (peef *PassportElementErrorFiles) PassportElementErrorSource() string {
|
||||
if peef == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return peef.Source
|
||||
}
|
||||
|
||||
func (peef *PassportElementErrorFiles) PassportElementErrorType() string {
|
||||
if peef == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return peef.Type
|
||||
}
|
||||
|
||||
func (peetf *PassportElementErrorTranslationFile) PassportElementErrorMessage() string {
|
||||
if peetf == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return peetf.Message
|
||||
}
|
||||
|
||||
func (peetf *PassportElementErrorTranslationFile) PassportElementErrorSource() string {
|
||||
if peetf == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return peetf.Source
|
||||
}
|
||||
|
||||
func (peetf *PassportElementErrorTranslationFile) PassportElementErrorType() string {
|
||||
if peetf == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return peetf.Type
|
||||
}
|
||||
|
||||
func (peetf *PassportElementErrorTranslationFiles) PassportElementErrorMessage() string {
|
||||
if peetf == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return peetf.Message
|
||||
}
|
||||
|
||||
func (peetf *PassportElementErrorTranslationFiles) PassportElementErrorSource() string {
|
||||
if peetf == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return peetf.Source
|
||||
}
|
||||
|
||||
func (peetf *PassportElementErrorTranslationFiles) PassportElementErrorType() string {
|
||||
if peetf == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return peetf.Type
|
||||
}
|
||||
|
||||
func (peeu *PassportElementErrorUnspecified) PassportElementErrorMessage() string {
|
||||
if peeu == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return peeu.Message
|
||||
}
|
||||
|
||||
func (peeu *PassportElementErrorUnspecified) PassportElementErrorSource() string {
|
||||
if peeu == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return peeu.Source
|
||||
}
|
||||
|
||||
func (peeu *PassportElementErrorUnspecified) PassportElementErrorType() string {
|
||||
if peeu == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return peeu.Type
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package telegram
|
||||
|
||||
func (pseoos *PassportScopeElementOneOfSeveral) PassportScopeElementTranslation() bool {
|
||||
if pseoos == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return pseoos.Translation
|
||||
}
|
||||
|
||||
func (pseoos *PassportScopeElementOneOfSeveral) PassportScopeElementSelfie() bool {
|
||||
if pseoos == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return pseoos.Selfie
|
||||
}
|
||||
|
||||
func (pseo *PassportScopeElementOne) PassportScopeElementTranslation() bool {
|
||||
if pseo == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return pseo.Translation
|
||||
}
|
||||
|
||||
func (pseo *PassportScopeElementOne) PassportScopeElementSelfie() bool {
|
||||
if pseo == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return pseo.Selfie
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package telegram
|
||||
|
||||
import "time"
|
||||
|
||||
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 {
|
||||
if pd == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return pd.FirstName + " " + pd.LastName
|
||||
}
|
||||
|
||||
func (pd *PersonalDetails) FullNameNative() string {
|
||||
if pd == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return pd.FirstNameNative + " " + pd.LastNameNative
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package telegram
|
||||
|
||||
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
|
||||
}
|
Loading…
Reference in New Issue