408 lines
18 KiB
Go
408 lines
18 KiB
Go
// Oracle generator for detz::wa M2 store vectors.
|
|
//
|
|
// Every value is produced by pinned whatsmeow itself (store/sqlstore over a
|
|
// scratch SQLite database), so the C++ store is checked against reference
|
|
// behavior, not against our own reimplementation. The op sequence below is
|
|
// replayed in order by tests/whatsapp_test.cpp (test_store_m2) against WaStore
|
|
// with detz-format signal addresses ("user.device" where the oracle uses
|
|
// whatsmeow's "user:device"); the JSON records observable outcomes, never
|
|
// addresses, so the comparison is format-agnostic. JID strings ARE compared
|
|
// byte-for-byte.
|
|
//
|
|
// Run from a module that requires go.mau.fi/whatsmeow and modernc.org/sqlite:
|
|
// go run store_oracle.go > store_vectors.json (inside such a module)
|
|
//go:build ignore
|
|
|
|
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
|
|
_ "modernc.org/sqlite"
|
|
|
|
"go.mau.fi/whatsmeow/proto/waAdv"
|
|
"go.mau.fi/whatsmeow/store"
|
|
"go.mau.fi/whatsmeow/store/sqlstore"
|
|
"go.mau.fi/whatsmeow/types"
|
|
)
|
|
|
|
var out = map[string]any{}
|
|
|
|
func set(k string, v any) { out[k] = v }
|
|
|
|
func must(err error, what string) {
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "oracle: %s: %v\n", what, err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func hx(b []byte) string { return hex.EncodeToString(b) }
|
|
|
|
func key(fill byte) [32]byte {
|
|
var k [32]byte
|
|
for i := range k {
|
|
k[i] = fill
|
|
}
|
|
return k
|
|
}
|
|
|
|
func jid(user, server string) types.JID { return types.NewJID(user, server) }
|
|
|
|
func main() {
|
|
ctx := context.Background()
|
|
tmp, err := os.CreateTemp("", "wa-m2-oracle-*.db")
|
|
must(err, "temp db")
|
|
path := tmp.Name()
|
|
tmp.Close()
|
|
defer os.Remove(path)
|
|
|
|
container, err := sqlstore.New(ctx, "sqlite", "file:"+path+"?_foreign_keys=on", nil)
|
|
must(err, "sqlstore.New")
|
|
// A saved device row (the store tables key their rows to it by foreign
|
|
// key); the keys are random, only the row's presence matters here.
|
|
ourJID := jid("15550000000", types.DefaultUserServer)
|
|
full := container.NewDevice()
|
|
full.ID = &ourJID
|
|
full.Account = &waAdv.ADVSignedDeviceIdentity{Details: []byte{0}, AccountSignature: make([]byte, 64), AccountSignatureKey: make([]byte, 32), DeviceSignature: make([]byte, 64)}
|
|
must(full.Save(ctx), "device Save")
|
|
inner := sqlstore.NewSQLStore(container, ourJID)
|
|
var s store.SessionStore = inner
|
|
var idn store.IdentityStore = inner
|
|
var senderKeys store.SenderKeyStore = inner
|
|
var contacts store.ContactStore = inner
|
|
var chats store.ChatSettingsStore = inner
|
|
var secrets store.MsgSecretStore = inner
|
|
var tokens store.PrivacyTokenStore = inner
|
|
var lids store.LIDStore = container.LIDMap
|
|
dev := &store.Device{LIDs: container.LIDMap} // GetAltJID only consults LIDs
|
|
|
|
set("muted_forever_unix", store.MutedForever.Unix())
|
|
|
|
// --- JID normalization (types.JID; replayed against WaJid) ---
|
|
jids := []string{
|
|
"15551234567@s.whatsapp.net",
|
|
"15551234567:3@s.whatsapp.net",
|
|
"15551234567.4:3@s.whatsapp.net",
|
|
"s.whatsapp.net",
|
|
"1234@lid",
|
|
"1234:7@lid",
|
|
"a@b@c",
|
|
"120363000000@g.us",
|
|
}
|
|
norm := map[string]string{}
|
|
for _, raw := range jids {
|
|
parsed, err := types.ParseJID(raw)
|
|
must(err, "parse "+raw)
|
|
norm[raw] = parsed.ToNonAD().String()
|
|
set("signal_user:"+raw, parsed.SignalAddressUser())
|
|
}
|
|
set("jid_non_ad", norm)
|
|
badJIDs := []string{"", "@", "user@", "a.b.c@s.whatsapp.net", "u:x@s.whatsapp.net", "u.1.2@s.whatsapp.net", "u.1:2:3@s.whatsapp.net"}
|
|
bad := map[string]bool{}
|
|
for _, raw := range badJIDs {
|
|
_, err := types.ParseJID(raw)
|
|
bad[raw] = err != nil
|
|
}
|
|
set("jid_parse_fails", bad)
|
|
|
|
// --- identities ---
|
|
a1 := "15551234567:0"
|
|
set("trust_unknown", mustTrust(ctx, idn, a1, key(1)))
|
|
must(idn.PutIdentity(ctx, a1, key(1)), "PutIdentity")
|
|
set("trust_same", mustTrust(ctx, idn, a1, key(1)))
|
|
set("trust_other", mustTrust(ctx, idn, a1, key(2)))
|
|
must(idn.PutIdentity(ctx, a1, key(2)), "PutIdentity overwrite")
|
|
set("trust_after_overwrite_old", mustTrust(ctx, idn, a1, key(1)))
|
|
set("trust_after_overwrite_new", mustTrust(ctx, idn, a1, key(2)))
|
|
must(idn.PutIdentity(ctx, "15551234567:5", key(3)), "PutIdentity second device")
|
|
must(idn.DeleteIdentity(ctx, a1), "DeleteIdentity")
|
|
set("trust_after_delete", mustTrust(ctx, idn, a1, key(2)))
|
|
set("trust_sibling_after_delete", mustTrust(ctx, idn, "15551234567:5", key(3)))
|
|
must(idn.DeleteAllIdentities(ctx, "15551234567"), "DeleteAllIdentities")
|
|
set("trust_sibling_after_delete_all", mustTrust(ctx, idn, "15551234567:5", key(3)))
|
|
// Upstream DeleteIdentity accidentally uses the LIKE query: an address
|
|
// holding '%' deletes more rows. detz fixes this (exact match); the C++
|
|
// test asserts the fixed behavior and this records what upstream does.
|
|
must(idn.PutIdentity(ctx, "9%9:0", key(4)), "PutIdentity pct")
|
|
must(idn.PutIdentity(ctx, "999:0", key(5)), "PutIdentity pct sibling")
|
|
must(idn.DeleteIdentity(ctx, "9%9:0"), "DeleteIdentity pct")
|
|
set("trust_pct_sibling_after_pct_delete", mustTrust(ctx, idn, "999:0", key(5)))
|
|
|
|
// --- sessions ---
|
|
set("has_session_missing", mustHas(ctx, s, "15550001111:0"))
|
|
must(s.PutSession(ctx, "15550001111:0", []byte("sess-aaa")), "PutSession")
|
|
must(s.PutSession(ctx, "15550001111:2", []byte("sess-bbb")), "PutSession 2")
|
|
set("has_session_present", mustHas(ctx, s, "15550001111:0"))
|
|
set("get_session", hx(mustGet(ctx, s, "15550001111:0")))
|
|
set("get_session_missing_null", mustGet(ctx, s, "15550009999:0") == nil)
|
|
many, err := s.GetManySessions(ctx, []string{"15550001111:0", "15550009999:0", "15550001111:2"})
|
|
must(err, "GetManySessions")
|
|
set("get_many_present", hx(many["15550001111:0"]))
|
|
set("get_many_missing_null", many["15550009999:0"] == nil)
|
|
set("get_many_all_keys", len(many) == 3)
|
|
emptyMany, err := s.GetManySessions(ctx, nil)
|
|
must(err, "GetManySessions empty")
|
|
set("get_many_empty_null", emptyMany == nil)
|
|
must(s.PutManySessions(ctx, map[string][]byte{"15550002222:0": []byte("sess-ccc")}), "PutManySessions")
|
|
set("get_many_put", hx(mustGet(ctx, s, "15550002222:0")))
|
|
must(s.DeleteSession(ctx, "15550001111:2"), "DeleteSession")
|
|
set("has_session_after_delete", mustHas(ctx, s, "15550001111:2"))
|
|
must(s.DeleteAllSessions(ctx, "15550001111"), "DeleteAllSessions")
|
|
set("has_session_after_delete_all", mustHas(ctx, s, "15550001111:0"))
|
|
set("has_other_after_delete_all", mustHas(ctx, s, "15550002222:0"))
|
|
|
|
// --- migrate PN -> LID (sessions + identities + sender keys) ---
|
|
// Upstream renames over signal users, so the LID-side address embeds the
|
|
// agent ("100000000000001_1:0"); detz renames plain users ("...001.0").
|
|
// The vectors pin the upstream spelling; the C++ test asserts its own.
|
|
pn := jid("15550003333", types.DefaultUserServer)
|
|
lid := jid("100000000000001", types.HiddenUserServer)
|
|
pnAddr := pn.SignalAddressUser() + ":0"
|
|
lidAddr := lid.SignalAddressUser() + ":0"
|
|
set("mig_lid_addr", lidAddr)
|
|
must(s.PutSession(ctx, pnAddr, []byte("sess-mig")), "PutSession mig")
|
|
must(idn.PutIdentity(ctx, pnAddr, key(6)), "PutIdentity mig")
|
|
must(senderKeys.PutSenderKey(ctx, "group@g.us", pnAddr, []byte("sender-mig")), "PutSenderKey mig")
|
|
must(s.MigratePNToLID(ctx, pn, lid), "MigratePNToLID")
|
|
set("mig_session_moved", hx(mustGet(ctx, s, lidAddr)))
|
|
set("mig_session_gone", mustGet(ctx, s, pnAddr) == nil)
|
|
set("mig_identity_moved", mustTrust(ctx, idn, lidAddr, key(6)))
|
|
set("mig_identity_gone", mustTrust(ctx, idn, pnAddr, key(6)))
|
|
sk, err := senderKeys.GetSenderKey(ctx, "group@g.us", lidAddr)
|
|
must(err, "GetSenderKey migrated")
|
|
set("mig_sender_moved", hx(sk))
|
|
skOld, err := senderKeys.GetSenderKey(ctx, "group@g.us", pnAddr)
|
|
must(err, "GetSenderKey old")
|
|
set("mig_sender_gone", skOld == nil)
|
|
must(s.MigratePNToLID(ctx, pn, lid), "MigratePNToLID repeat")
|
|
set("mig_repeat_still_moved", hx(mustGet(ctx, s, lidAddr)))
|
|
|
|
// --- LID map ---
|
|
pnA := jid("15551112222", types.DefaultUserServer)
|
|
lidA := jid("100000000000002", types.HiddenUserServer)
|
|
_, err = lids.GetLIDForPN(ctx, pnA)
|
|
set("lid_miss_empty", err == nil)
|
|
must(lids.PutLIDMapping(ctx, lidA, pnA), "PutLIDMapping")
|
|
gotLID, err := lids.GetLIDForPN(ctx, pnA)
|
|
must(err, "GetLIDForPN")
|
|
set("lid_hit", gotLID.String())
|
|
pnDev := types.JID{User: "15551112222", Device: 3, Server: types.DefaultUserServer}
|
|
gotLIDDev, err := lids.GetLIDForPN(ctx, pnDev)
|
|
must(err, "GetLIDForPN device")
|
|
set("lid_hit_device", gotLIDDev.String())
|
|
gotPN, err := lids.GetPNForLID(ctx, lidA)
|
|
must(err, "GetPNForLID")
|
|
set("pn_hit", gotPN.String())
|
|
_, err = lids.GetLIDForPN(ctx, lidA)
|
|
set("lid_for_pn_rejects_lid", err != nil)
|
|
_, err = lids.GetPNForLID(ctx, pnA)
|
|
set("pn_for_lid_rejects_pn", err != nil)
|
|
set("put_mapping_rejects_swapped", lids.PutLIDMapping(ctx, pnA, lidA) != nil)
|
|
must(lids.PutManyLIDMappings(ctx, []store.LIDMapping{
|
|
{LID: jid("100000000000003", types.HiddenUserServer), PN: jid("15551113333", types.DefaultUserServer)},
|
|
{LID: jid("100000000000003", types.HiddenUserServer), PN: jid("15551113333", types.DefaultUserServer)},
|
|
{LID: pnA, PN: lidA}, // invalid: skipped, not an error
|
|
}), "PutManyLIDMappings")
|
|
multi, err := lids.GetManyLIDsForPNs(ctx, []types.JID{pnA, jid("15551113333", types.DefaultUserServer), jid("19998887777", types.DefaultUserServer), lidA})
|
|
must(err, "GetManyLIDsForPNs")
|
|
set("many_lids_hit", multi[pnA].String())
|
|
set("many_lids_new", multi[jid("15551113333", types.DefaultUserServer)].String())
|
|
_, missing := multi[jid("19998887777", types.DefaultUserServer)]
|
|
set("many_lids_missing_absent", !missing)
|
|
set("many_lids_size", len(multi))
|
|
// Remapping a PN to a new LID drops the old reverse mapping.
|
|
must(lids.PutLIDMapping(ctx, jid("100000000000004", types.HiddenUserServer), pnA), "PutLIDMapping remap")
|
|
remapped, err := lids.GetLIDForPN(ctx, pnA)
|
|
must(err, "GetLIDForPN remapped")
|
|
set("lid_remapped", remapped.String())
|
|
oldPN, err := lids.GetPNForLID(ctx, lidA)
|
|
must(err, "GetPNForLID stale")
|
|
set("lid_remap_old_gone", oldPN.String() == "")
|
|
// GetAltJID routing.
|
|
altPN, _ := dev.GetAltJID(ctx, pnA)
|
|
set("alt_pn", altPN.String())
|
|
altLID, _ := dev.GetAltJID(ctx, jid("100000000000004", types.HiddenUserServer))
|
|
set("alt_lid", altLID.String())
|
|
altGroup, _ := dev.GetAltJID(ctx, jid("120363000000", types.GroupServer))
|
|
set("alt_group_empty", altGroup.String() == "")
|
|
must(container.LIDMap.FillCache(ctx), "FillCache")
|
|
|
|
// --- contacts ---
|
|
u1 := jid("15552223333", types.DefaultUserServer)
|
|
changed, prev, err := contacts.PutPushName(ctx, u1, "Pushee")
|
|
must(err, "PutPushName")
|
|
set("push_first_changed", changed)
|
|
set("push_first_prev", prev)
|
|
changed, prev, err = contacts.PutPushName(ctx, u1, "Pushee")
|
|
must(err, "PutPushName same")
|
|
set("push_same_changed", changed)
|
|
changed, prev, err = contacts.PutPushName(ctx, u1, "Pushed")
|
|
must(err, "PutPushName change")
|
|
set("push_change_changed", changed)
|
|
set("push_change_prev", prev)
|
|
changed, _, err = contacts.PutBusinessName(ctx, u1, "Biz Co")
|
|
must(err, "PutBusinessName")
|
|
set("biz_first_changed", changed)
|
|
must(contacts.PutContactName(ctx, u1, "First", "First Last"), "PutContactName")
|
|
ci, err := contacts.GetContact(ctx, u1)
|
|
must(err, "GetContact")
|
|
set("contact_found", ci.Found)
|
|
set("contact_first", ci.FirstName)
|
|
set("contact_full", ci.FullName)
|
|
set("contact_push", ci.PushName)
|
|
set("contact_biz", ci.BusinessName)
|
|
missing2, err := contacts.GetContact(ctx, jid("15550004444", types.DefaultUserServer))
|
|
must(err, "GetContact missing")
|
|
set("contact_missing_found", missing2.Found)
|
|
must(contacts.PutAllContactNames(ctx, []store.ContactEntry{
|
|
{JID: jid("15550005555", types.DefaultUserServer), FirstName: "A", FullName: "A A"},
|
|
{JID: jid("15550005555", types.DefaultUserServer), FirstName: "B", FullName: "B B"},
|
|
{JID: jid("15550006666", types.DefaultUserServer), FirstName: "C", FullName: "C C"},
|
|
}), "PutAllContactNames")
|
|
dedup, err := contacts.GetContact(ctx, jid("15550005555", types.DefaultUserServer))
|
|
must(err, "GetContact dedup")
|
|
set("contact_dedup_first", dedup.FirstName)
|
|
must(contacts.PutManyRedactedPhones(ctx, []store.RedactedPhoneEntry{
|
|
{JID: jid("100000000000005", types.HiddenUserServer), RedactedPhone: "+1········80"},
|
|
}), "PutManyRedactedPhones")
|
|
red, err := contacts.GetContact(ctx, jid("100000000000005", types.HiddenUserServer))
|
|
must(err, "GetContact redacted")
|
|
set("contact_redacted", red.RedactedPhone)
|
|
all, err := contacts.GetAllContacts(ctx)
|
|
must(err, "GetAllContacts")
|
|
set("contact_all_has_u1", all[u1].PushName == "Pushed")
|
|
set("contact_all_count_ge", len(all) >= 4)
|
|
|
|
// --- chat settings ---
|
|
chat := jid("15553334444", types.DefaultUserServer)
|
|
group := jid("120363000001", types.GroupServer)
|
|
cs, err := chats.GetChatSettings(ctx, chat)
|
|
must(err, "GetChatSettings missing")
|
|
set("chat_missing_found", cs.Found)
|
|
set("chat_missing_muted", cs.MutedUntil.Unix())
|
|
set("chat_missing_muted_zero", cs.MutedUntil.IsZero())
|
|
must(chats.PutMutedUntil(ctx, chat, time.Unix(1700000000, 0)), "PutMutedUntil")
|
|
must(chats.PutPinned(ctx, chat, true), "PutPinned")
|
|
must(chats.PutArchived(ctx, chat, true), "PutArchived")
|
|
cs, err = chats.GetChatSettings(ctx, chat)
|
|
must(err, "GetChatSettings set")
|
|
set("chat_muted", cs.MutedUntil.Unix())
|
|
set("chat_pinned", cs.Pinned)
|
|
set("chat_archived", cs.Archived)
|
|
set("chat_found", cs.Found)
|
|
must(chats.PutMutedUntil(ctx, chat, store.MutedForever), "PutMutedUntil forever")
|
|
cs, err = chats.GetChatSettings(ctx, chat)
|
|
must(err, "GetChatSettings forever")
|
|
set("chat_forever", cs.MutedUntil.Equal(store.MutedForever))
|
|
must(chats.PutMutedUntil(ctx, chat, time.Time{}), "PutMutedUntil zero")
|
|
cs, err = chats.GetChatSettings(ctx, chat)
|
|
must(err, "GetChatSettings zero")
|
|
set("chat_unmuted", cs.MutedUntil.Unix())
|
|
set("chat_unmuted_zero", cs.MutedUntil.IsZero())
|
|
must(chats.PutPinned(ctx, chat, false), "PutPinned false")
|
|
cs, _ = chats.GetChatSettings(ctx, chat)
|
|
set("chat_unpinned", !cs.Pinned && cs.Archived)
|
|
must(chats.PutWASARootSecretID(ctx, group, "wasa-id-1"), "PutWASARootSecretID")
|
|
wasa, err := chats.GetWASARootSecretID(ctx, group)
|
|
must(err, "GetWASARootSecretID")
|
|
set("wasa_hit", string(wasa))
|
|
wasaMissing, err := chats.GetWASARootSecretID(ctx, chat)
|
|
must(err, "GetWASARootSecretID missing")
|
|
set("wasa_missing_empty", string(wasaMissing) == "")
|
|
|
|
// --- message secrets ---
|
|
pnB := jid("15554445555", types.DefaultUserServer)
|
|
lidB := jid("100000000000006", types.HiddenUserServer)
|
|
must(lids.PutLIDMapping(ctx, lidB, pnB), "PutLIDMapping secrets")
|
|
must(secrets.PutMessageSecret(ctx, pnB, pnB, "MSGID1", bytes.Repeat([]byte{0x42}, 32)), "PutMessageSecret")
|
|
sec, realSender, err := secrets.GetMessageSecret(ctx, pnB, pnB, "MSGID1")
|
|
must(err, "GetMessageSecret")
|
|
set("secret_hit", hx(sec))
|
|
set("secret_sender", realSender.String())
|
|
must(secrets.PutMessageSecret(ctx, pnB, pnB, "MSGID1", bytes.Repeat([]byte{0x43}, 32)), "PutMessageSecret dup")
|
|
sec, _, _ = secrets.GetMessageSecret(ctx, pnB, pnB, "MSGID1")
|
|
set("secret_dup_keeps_first", hx(sec))
|
|
secAlt, realAlt, err := secrets.GetMessageSecret(ctx, lidB, lidB, "MSGID1")
|
|
must(err, "GetMessageSecret alt")
|
|
set("secret_alt_hit", hx(secAlt))
|
|
set("secret_alt_sender", realAlt.String())
|
|
secMiss, _, err := secrets.GetMessageSecret(ctx, pnB, pnB, "NOPE")
|
|
must(err, "GetMessageSecret miss")
|
|
set("secret_miss_null", secMiss == nil)
|
|
must(secrets.PutMessageSecrets(ctx, []store.MessageSecretInsert{
|
|
{Chat: pnB, Sender: pnB, ID: "MSGID2", Secret: []byte("s2")},
|
|
{Chat: pnB, Sender: pnB, ID: "MSGID3"}, // empty secret: skipped
|
|
{Chat: types.EmptyJID, Sender: pnB, ID: "MSGID4", Secret: []byte("s4")},
|
|
}), "PutMessageSecrets")
|
|
sec2, _, _ := secrets.GetMessageSecret(ctx, pnB, pnB, "MSGID2")
|
|
set("secret_batch_hit", hx(sec2))
|
|
sec3, _, _ := secrets.GetMessageSecret(ctx, pnB, pnB, "MSGID3")
|
|
set("secret_batch_skipped", sec3 == nil)
|
|
|
|
// --- privacy tokens ---
|
|
t1 := store.PrivacyToken{User: pnB, Token: []byte("tok-1"), Timestamp: time.Unix(1700000000, 0)}
|
|
must(tokens.PutPrivacyTokens(ctx, t1), "PutPrivacyTokens")
|
|
got, err := tokens.GetPrivacyToken(ctx, pnB)
|
|
must(err, "GetPrivacyToken")
|
|
set("token_hit", hx(got.Token))
|
|
set("token_ts", got.Timestamp.Unix())
|
|
set("token_sender_ts_zero", got.SenderTimestamp.IsZero())
|
|
older := store.PrivacyToken{User: pnB, Token: []byte("tok-old"), Timestamp: time.Unix(1600000000, 0)}
|
|
must(tokens.PutPrivacyTokens(ctx, older), "PutPrivacyTokens older")
|
|
got, _ = tokens.GetPrivacyToken(ctx, pnB)
|
|
set("token_older_ignored", hx(got.Token))
|
|
withSender := store.PrivacyToken{User: pnB, Token: []byte("tok-2"), Timestamp: time.Unix(1700000001, 0), SenderTimestamp: time.Unix(1700000002, 0)}
|
|
must(tokens.PutPrivacyTokens(ctx, withSender), "PutPrivacyTokens newer")
|
|
got, _ = tokens.GetPrivacyToken(ctx, pnB)
|
|
set("token_newer_wins", hx(got.Token))
|
|
set("token_sender_ts", got.SenderTimestamp.Unix())
|
|
noSender := store.PrivacyToken{User: pnB, Token: []byte("tok-3"), Timestamp: time.Unix(1700000003, 0)}
|
|
must(tokens.PutPrivacyTokens(ctx, noSender), "PutPrivacyTokens no sender ts")
|
|
got, _ = tokens.GetPrivacyToken(ctx, pnB)
|
|
set("token_sender_ts_kept", got.SenderTimestamp.Unix())
|
|
gotAlt, err := tokens.GetPrivacyToken(ctx, lidB)
|
|
must(err, "GetPrivacyToken alt")
|
|
set("token_alt_hit", hx(gotAlt.Token))
|
|
set("token_alt_user", gotAlt.User.String())
|
|
must(tokens.PutPrivacyTokens(ctx,
|
|
store.PrivacyToken{User: jid("15550007777", types.DefaultUserServer), Token: []byte("tok-x"), Timestamp: time.Unix(1500000000, 0)},
|
|
store.PrivacyToken{User: jid("15550008888", types.DefaultUserServer), Token: []byte("tok-y"), Timestamp: time.Unix(1800000000, 0)},
|
|
), "PutPrivacyTokens batch")
|
|
n, err := tokens.DeleteExpiredPrivacyTokens(ctx, time.Unix(1600000000, 0))
|
|
must(err, "DeleteExpiredPrivacyTokens")
|
|
set("token_expired_deleted", n)
|
|
gotX, _ := tokens.GetPrivacyToken(ctx, jid("15550007777", types.DefaultUserServer))
|
|
set("token_expired_gone", gotX == nil)
|
|
set("put_tokens_empty_err", tokens.PutPrivacyTokens(ctx) != nil)
|
|
|
|
raw, err := json.MarshalIndent(out, "", " ")
|
|
must(err, "marshal")
|
|
os.Stdout.Write(raw)
|
|
os.Stdout.Write([]byte("\n"))
|
|
}
|
|
|
|
func mustTrust(ctx context.Context, idn store.IdentityStore, addr string, k [32]byte) bool {
|
|
t, err := idn.IsTrustedIdentity(ctx, addr, k)
|
|
must(err, "IsTrustedIdentity "+addr)
|
|
return t
|
|
}
|
|
|
|
func mustHas(ctx context.Context, s store.SessionStore, addr string) bool {
|
|
h, err := s.HasSession(ctx, addr)
|
|
must(err, "HasSession "+addr)
|
|
return h
|
|
}
|
|
|
|
func mustGet(ctx context.Context, s store.SessionStore, addr string) []byte {
|
|
b, err := s.GetSession(ctx, addr)
|
|
must(err, "GetSession "+addr)
|
|
return b
|
|
}
|