9acf6ab3b4
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 12s
CI / integration (pull_request) Successful in 20s
CI / ui (pull_request) Successful in 1m9s
CI / conformance (pull_request) Successful in 11s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 2m5s
Testing the rewarded slice surfaced a contradiction: rewarded ads let a VK-iOS
user earn vk chips, but the blanket VK-iOS "spend freeze" then blocked spending
them (the wallet showed "5 (view-only)"). Apple's ToS forbids only BUYING in-app
values on VK-iOS (money -> chips), not spending or earning them — so the freeze is
corrected to purchase-only: vkFrozen() now gates only CreateOrder (the money-in
step), not spendableSources (spending). VK-wallet chips — earned via rewarded ads
or bought on the same account elsewhere (VK Android) — now spend on VK-iOS too.
(Owner's ToS finding.)
Also: the temporary contour diagnostic confirmed VK returns only {result:true} for
a rewarded view (no token/signature) — client-attested is final, no hardening
possible — so the diagnostic (the log and the diag wire field) is removed.
Docs: PAYMENTS(+ru) VK-iOS freeze + D17 amend + PLAN E6. Tests updated (gate /
wallet VK-iOS now spendable).
43 lines
1.2 KiB
Go
43 lines
1.2 KiB
Go
package payments
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// gateOnlyService builds a Service with a fixed clock and no store, usable only for the CreateOrder
|
|
// gate rejections that return before any store access.
|
|
func gateOnlyService() *Service {
|
|
return &Service{clock: func() time.Time { return time.Unix(0, 0).UTC() }}
|
|
}
|
|
|
|
// TestCreateOrderGateRejections checks that CreateOrder fails closed — before touching the store —
|
|
// on an untrusted platform, the VK-iOS spend freeze, and a method whose funding segment the account
|
|
// does not hold.
|
|
func TestCreateOrderGateRejections(t *testing.T) {
|
|
ctx := context.Background()
|
|
acc, prod := uuid.New(), uuid.New()
|
|
present := []Source{SourceDirect, SourceVK}
|
|
|
|
cases := []struct {
|
|
name string
|
|
cxt Context
|
|
}{
|
|
{"untrusted context", Context{}},
|
|
{"vk-ios purchase freeze", Context{Kind: SourceVK, Subtype: SubtypeIOS}},
|
|
{"method segment not attached", Context{Kind: SourceTelegram}},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := gateOnlyService().CreateOrder(ctx, acc, tc.cxt, present, prod, "robokassa")
|
|
if !errors.Is(err, ErrUntrusted) {
|
|
t.Fatalf("CreateOrder(%s) = %v, want ErrUntrusted", tc.name, err)
|
|
}
|
|
})
|
|
}
|
|
}
|