fix: allow optional digital RMB code and inline payment password setup
This commit is contained in:
@@ -301,9 +301,14 @@ func (s *Service) CreatePaymentAccount(ctx context.Context, tenantID, memberID i
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
digitalRMBCodeCipher, err := s.encrypt(input.DigitalRMBCode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
digitalRMBCodeCipher, digitalRMBCodeHash, digitalRMBCodeMask := "", "", ""
|
||||
if input.DigitalRMBCode != "" {
|
||||
digitalRMBCodeCipher, err = s.encrypt(input.DigitalRMBCode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
digitalRMBCodeHash = s.lookupHash(input.DigitalRMBCode)
|
||||
digitalRMBCodeMask = maskAccount(input.DigitalRMBCode)
|
||||
}
|
||||
row, err := s.repository.CreatePaymentAccount(ctx, store.PaymentAccountCreation{
|
||||
TenantID: tenantID, MemberID: memberID, AccountType: 1, BankCode: "BANK", BankName: input.BankName,
|
||||
@@ -311,8 +316,8 @@ func (s *Service) CreatePaymentAccount(ctx context.Context, tenantID, memberID i
|
||||
IdentityNoCipher: identityNoCipher, IdentityNoHash: s.lookupHash(input.IdentityNo),
|
||||
IdentityNoMask: maskIdentityNo(input.IdentityNo), AccountNoCipher: accountCipher,
|
||||
AccountNoHash: s.lookupHash(input.AccountNo), AccountNoMask: maskAccount(input.AccountNo),
|
||||
DigitalRMBCodeCipher: digitalRMBCodeCipher, DigitalRMBCodeHash: s.lookupHash(input.DigitalRMBCode),
|
||||
DigitalRMBCodeMask: maskAccount(input.DigitalRMBCode),
|
||||
DigitalRMBCodeCipher: digitalRMBCodeCipher, DigitalRMBCodeHash: digitalRMBCodeHash,
|
||||
DigitalRMBCodeMask: digitalRMBCodeMask,
|
||||
WechatQRAttachmentID: input.WechatQRAttachmentID,
|
||||
AlipayQRAttachmentID: input.AlipayQRAttachmentID,
|
||||
})
|
||||
@@ -759,7 +764,7 @@ func normalizePaymentAccount(input *PaymentAccountInput) error {
|
||||
if !validHumanName(input.HolderName) || !identityNoPattern.MatchString(input.IdentityNo) ||
|
||||
utf8.RuneCountInString(input.BankName) < 2 || utf8.RuneCountInString(input.BankName) > 100 ||
|
||||
len(input.AccountNo) < 8 || len(input.AccountNo) > 32 || !allDigits(input.AccountNo) ||
|
||||
len(input.DigitalRMBCode) < 6 || len(input.DigitalRMBCode) > 32 || !allDigits(input.DigitalRMBCode) ||
|
||||
(input.DigitalRMBCode != "" && (len(input.DigitalRMBCode) < 6 || len(input.DigitalRMBCode) > 32 || !allDigits(input.DigitalRMBCode))) ||
|
||||
input.WechatQRAttachmentID <= 0 || input.AlipayQRAttachmentID <= 0 ||
|
||||
input.WechatQRAttachmentID == input.AlipayQRAttachmentID {
|
||||
return ErrAccountFieldsInvalid
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"git.118im.com/im_team/olons_server/internal/config"
|
||||
"git.118im.com/im_team/olons_server/internal/store"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
type fakeRepository struct {
|
||||
@@ -23,6 +24,16 @@ type fakeRepository struct {
|
||||
createdRecharge store.RechargeCreation
|
||||
}
|
||||
|
||||
type paymentAccountRepository struct {
|
||||
fakeRepository
|
||||
created store.PaymentAccountCreation
|
||||
}
|
||||
|
||||
func (f *paymentAccountRepository) CreatePaymentAccount(_ context.Context, input store.PaymentAccountCreation) (*store.PaymentAccount, error) {
|
||||
f.created = input
|
||||
return &store.PaymentAccount{ID: 1, AccountType: input.AccountType}, nil
|
||||
}
|
||||
|
||||
func (f *fakeRepository) CurrentSiteConfig(context.Context, int64) (json.RawMessage, error) {
|
||||
return f.config, nil
|
||||
}
|
||||
@@ -115,6 +126,36 @@ func TestNormalizePaymentAccount(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizePaymentAccountAllowsEmptyDigitalRMBCode(t *testing.T) {
|
||||
input := PaymentAccountInput{BankName: "中国工商银行", HolderName: "张三",
|
||||
IdentityNo: "11010119900101123X", AccountNo: "6222000000001234",
|
||||
WechatQRAttachmentID: 8, AlipayQRAttachmentID: 9}
|
||||
if err := normalizePaymentAccount(&input); err != nil {
|
||||
t.Fatalf("empty digital RMB code should be optional: %v", err)
|
||||
}
|
||||
input.DigitalRMBCode = "1234"
|
||||
if err := normalizePaymentAccount(&input); !errors.Is(err, ErrAccountFieldsInvalid) {
|
||||
t.Fatalf("short non-empty digital RMB code should be rejected: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreatePaymentAccountDoesNotStoreEmptyDigitalRMBCode(t *testing.T) {
|
||||
repository := &paymentAccountRepository{}
|
||||
service := New(repository, &redis.Client{}, config.AuthConfig{
|
||||
FinanceMasterKey: "test-finance-master-key-with-at-least-32-characters",
|
||||
})
|
||||
_, err := service.CreatePaymentAccount(context.Background(), 0, 1, PaymentAccountInput{
|
||||
BankName: "中国工商银行", HolderName: "张三", IdentityNo: "11010119900101123X",
|
||||
AccountNo: "6222000000001234", WechatQRAttachmentID: 8, AlipayQRAttachmentID: 9,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if repository.created.DigitalRMBCodeCipher != "" || repository.created.DigitalRMBCodeHash != "" || repository.created.DigitalRMBCodeMask != "" {
|
||||
t.Fatalf("empty digital RMB code must not be encrypted, hashed or masked: %#v", repository.created)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMaskAccountShortValueDoesNotLeak(t *testing.T) {
|
||||
if got := maskAccount("abcde"); got != "a***e" {
|
||||
t.Fatalf("unexpected mask %q", got)
|
||||
|
||||
Reference in New Issue
Block a user