Sync telesrv commits 49f9bab and 04d9563 into the public mirror. Exclude private docs and runtime key material per sync rules.
216 lines
6.2 KiB
Go
216 lines
6.2 KiB
Go
package rpc
|
|
|
|
import (
|
|
"encoding/json"
|
|
"telesrv/internal/domain"
|
|
|
|
"github.com/iamxvbaba/td/tg"
|
|
"sort"
|
|
)
|
|
|
|
func tgLangPackLanguages(items []domain.LangPackLanguage) []tg.LangPackLanguage {
|
|
out := make([]tg.LangPackLanguage, 0, len(items))
|
|
for _, item := range items {
|
|
out = append(out, tg.LangPackLanguage{
|
|
Official: item.Official,
|
|
Rtl: item.Rtl,
|
|
Beta: item.Beta,
|
|
Name: item.Name,
|
|
NativeName: item.NativeName,
|
|
LangCode: item.LangCode,
|
|
BaseLangCode: item.BaseLangCode,
|
|
PluralCode: item.PluralCode,
|
|
StringsCount: item.StringsCount,
|
|
TranslatedCount: item.TranslatedCount,
|
|
TranslationsURL: item.TranslationsURL,
|
|
})
|
|
}
|
|
return out
|
|
}
|
|
|
|
func tgLangPackStrings(items []domain.LangPackString) []tg.LangPackStringClass {
|
|
out := make([]tg.LangPackStringClass, 0, len(items))
|
|
for _, item := range items {
|
|
if item.Deleted {
|
|
out = append(out, &tg.LangPackStringDeleted{Key: item.Key})
|
|
continue
|
|
}
|
|
if item.Pluralized {
|
|
out = append(out, &tg.LangPackStringPluralized{
|
|
Key: item.Key,
|
|
ZeroValue: item.ZeroValue,
|
|
OneValue: item.OneValue,
|
|
TwoValue: item.TwoValue,
|
|
FewValue: item.FewValue,
|
|
ManyValue: item.ManyValue,
|
|
OtherValue: item.OtherValue,
|
|
})
|
|
continue
|
|
}
|
|
out = append(out, &tg.LangPackString{Key: item.Key, Value: item.Value})
|
|
}
|
|
return out
|
|
}
|
|
|
|
func tgPassword(settings domain.PasswordSettings) *tg.AccountPassword {
|
|
if len(settings.SecureRandom) == 0 {
|
|
settings.SecureRandom = []byte("telesrv-tdesktop-dev-secure-rand")
|
|
}
|
|
out := &tg.AccountPassword{
|
|
HasRecovery: settings.HasRecovery,
|
|
HasSecureValues: settings.HasSecureValues,
|
|
HasPassword: settings.HasPassword,
|
|
Hint: settings.Hint,
|
|
EmailUnconfirmedPattern: settings.EmailUnconfirmedPattern,
|
|
NewAlgo: tgPasswordAlgo(settings.NewAlgo),
|
|
NewSecureAlgo: tgSecurePasswordAlgo(settings.NewSecureAlgo),
|
|
SecureRandom: settings.SecureRandom,
|
|
LoginEmailPattern: settings.LoginEmailPattern,
|
|
}
|
|
if settings.HasPassword && settings.CurrentAlgo != nil {
|
|
out.CurrentAlgo = tgPasswordAlgo(*settings.CurrentAlgo)
|
|
out.SRPB = append([]byte(nil), settings.SRPB...)
|
|
out.SRPID = settings.SRPID
|
|
}
|
|
if settings.PendingResetDate != 0 {
|
|
out.PendingResetDate = settings.PendingResetDate
|
|
}
|
|
return out
|
|
}
|
|
|
|
func tgPasswordAlgo(algo domain.PasswordKDFAlgo) tg.PasswordKdfAlgoClass {
|
|
if len(algo.P) == 0 || algo.G == 0 {
|
|
return &tg.PasswordKdfAlgoUnknown{}
|
|
}
|
|
return &tg.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow{
|
|
Salt1: append([]byte(nil), algo.Salt1...),
|
|
Salt2: append([]byte(nil), algo.Salt2...),
|
|
G: algo.G,
|
|
P: append([]byte(nil), algo.P...),
|
|
}
|
|
}
|
|
|
|
func domainPasswordAlgo(in tg.PasswordKdfAlgoClass) (*domain.PasswordKDFAlgo, bool) {
|
|
if algo, ok := in.(*tg.PasswordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow); ok {
|
|
return &domain.PasswordKDFAlgo{
|
|
Salt1: append([]byte(nil), algo.Salt1...),
|
|
Salt2: append([]byte(nil), algo.Salt2...),
|
|
G: algo.G,
|
|
P: append([]byte(nil), algo.P...),
|
|
}, true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func tgSecurePasswordAlgo(algo domain.SecurePasswordKDFAlgo) tg.SecurePasswordKdfAlgoClass {
|
|
if algo.Kind == "pbkdf2_hmac_sha512_iter100000" {
|
|
return &tg.SecurePasswordKdfAlgoPBKDF2HMACSHA512iter100000{Salt: append([]byte(nil), algo.Salt...)}
|
|
}
|
|
return &tg.SecurePasswordKdfAlgoUnknown{}
|
|
}
|
|
|
|
func domainPasswordCheck(in tg.InputCheckPasswordSRPClass) domain.PasswordCheck {
|
|
if srp, ok := in.(*tg.InputCheckPasswordSRP); ok {
|
|
return domain.PasswordCheck{
|
|
SRPID: srp.SRPID,
|
|
A: append([]byte(nil), srp.A...),
|
|
M1: append([]byte(nil), srp.M1...),
|
|
}
|
|
}
|
|
return domain.PasswordCheck{Empty: true}
|
|
}
|
|
|
|
func domainPasswordInputSettings(in tg.AccountPasswordInputSettings) (domain.PasswordInputSettings, error) {
|
|
out := domain.PasswordInputSettings{}
|
|
if algo, ok := in.GetNewAlgo(); ok {
|
|
domainAlgo, ok := domainPasswordAlgo(algo)
|
|
if !ok {
|
|
return out, passwordHashInvalidErr()
|
|
}
|
|
out.NewAlgo = domainAlgo
|
|
out.NewPasswordHash = append([]byte(nil), in.NewPasswordHash...)
|
|
out.Hint = in.Hint
|
|
out.HasHint = true
|
|
}
|
|
if email, ok := in.GetEmail(); ok {
|
|
out.Email = email
|
|
out.HasEmail = true
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func tgPasswordSettings(settings domain.PrivatePasswordSettings) *tg.AccountPasswordSettings {
|
|
out := &tg.AccountPasswordSettings{}
|
|
if settings.Email != "" {
|
|
out.Email = settings.Email
|
|
}
|
|
return out
|
|
}
|
|
|
|
func tgCountriesList(list domain.CountriesList) tg.HelpCountriesListClass {
|
|
out := &tg.HelpCountriesList{
|
|
Hash: list.Hash,
|
|
Countries: make([]tg.HelpCountry, 0, len(list.Countries)),
|
|
}
|
|
for _, country := range list.Countries {
|
|
item := tg.HelpCountry{
|
|
Hidden: country.Hidden,
|
|
ISO2: country.ISO2,
|
|
DefaultName: country.DefaultName,
|
|
Name: country.Name,
|
|
CountryCodes: make([]tg.HelpCountryCode, 0, len(country.CountryCodes)),
|
|
}
|
|
for _, code := range country.CountryCodes {
|
|
item.CountryCodes = append(item.CountryCodes, tg.HelpCountryCode{
|
|
CountryCode: code.CountryCode,
|
|
Prefixes: code.Prefixes,
|
|
Patterns: code.Patterns,
|
|
})
|
|
}
|
|
out.Countries = append(out.Countries, item)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func tgJSONValue(data []byte) tg.JSONValueClass {
|
|
if len(data) == 0 {
|
|
return &tg.JSONObject{}
|
|
}
|
|
var v any
|
|
if err := json.Unmarshal(data, &v); err != nil {
|
|
return &tg.JSONObject{}
|
|
}
|
|
return tgJSON(v)
|
|
}
|
|
|
|
func tgJSON(v any) tg.JSONValueClass {
|
|
switch x := v.(type) {
|
|
case nil:
|
|
return &tg.JSONNull{}
|
|
case bool:
|
|
return &tg.JSONBool{Value: x}
|
|
case float64:
|
|
return &tg.JSONNumber{Value: x}
|
|
case string:
|
|
return &tg.JSONString{Value: x}
|
|
case []any:
|
|
arr := &tg.JSONArray{Value: make([]tg.JSONValueClass, 0, len(x))}
|
|
for _, item := range x {
|
|
arr.Value = append(arr.Value, tgJSON(item))
|
|
}
|
|
return arr
|
|
case map[string]any:
|
|
obj := &tg.JSONObject{Value: make([]tg.JSONObjectValue, 0, len(x))}
|
|
keys := make([]string, 0, len(x))
|
|
for key := range x {
|
|
keys = append(keys, key)
|
|
}
|
|
sort.Strings(keys)
|
|
for _, key := range keys {
|
|
obj.Value = append(obj.Value, tg.JSONObjectValue{Key: key, Value: tgJSON(x[key])})
|
|
}
|
|
return obj
|
|
default:
|
|
return &tg.JSONString{Value: ""}
|
|
}
|
|
}
|