/
githubmirror
/
client
Обзор
Документация
Войти
/
githubmirror
/
client
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
go/engine/track_proof_test.go
669 строк
20 KB
Marcel O'Neil
Migrate to Go Modules (#24023)
22 ноя 2021, 20:07
Не верифицирован
22 ноя 2021, 20:07
a66861b
Код
Авторство
О чём код?
// Copyright 2015 Keybase, Inc. All rights reserved. Use of // this source code is governed by the included BSD license. package engine import ( "fmt" "sort" "testing" "github.com/keybase/client/go/libkb" keybase1 "github.com/keybase/client/go/protocol/keybase1" "github.com/stretchr/testify/require" ) // testing service block type sb struct { social bool id string proofState keybase1.ProofState } func checkTrack(tc libkb.TestContext, fu *FakeUser, username string, blocks []sb, outcome *keybase1.IdentifyOutcome, sigVersion libkb.SigVersion) error { ui, them, err := runTrack(tc, fu, username, sigVersion) if err != nil { return err } return checkTrackCommon(tc, blocks, outcome, them, ui) } func checkTrackForce(tc libkb.TestContext, fu *FakeUser, username string, blocks []sb, outcome *keybase1.IdentifyOutcome) error { ui, them, err := runTrackWithOptions(tc, fu, username, keybase1.TrackOptions{BypassConfirm: true}, fu.NewSecretUI(), true) if err != nil { return err } return checkTrackCommon(tc, blocks, outcome, them, ui) } func checkTrackCommon(tc libkb.TestContext, blocks []sb, outcome *keybase1.IdentifyOutcome, them *libkb.User, ui *FakeIdentifyUI) error { me, err := libkb.LoadMe(libkb.NewLoadUserArg(tc.G)) if err != nil { return err } if them == nil { tc.T.Fatal("checkTrackCommon called with nil 'them' user") } m := NewMetaContextForTest(tc) s, err := me.TrackChainLinkFor(m, them.GetNormalizedName(), them.GetUID()) if err != nil { return err } if s == nil { tc.T.Fatal("me.TrackChainLinkFor(...) returned nil, nil") } else { tc.T.Logf("payload json:\n%s", s.UnmarshalPayloadJSON().MarshalPretty()) } sbs := s.ToServiceBlocks() if len(sbs) != len(blocks) { return fmt.Errorf("num service blocks: %d, expected %d", len(sbs), len(blocks)) } sort.Sort(byID(sbs)) for i, sb := range sbs { tsb := blocks[i] if sb.IsSocial() != tsb.social { return fmt.Errorf("(sb %d): social: %v, expected %v", i, sb.IsSocial(), tsb.social) } if sb.ToIDString() != tsb.id { return fmt.Errorf("(sb %d): id: %s, expected %s", i, sb.ToIDString(), tsb.id) } if sb.GetProofState() != tsb.proofState { return fmt.Errorf("(sb %d): proof state: %d, expected %d", i, sb.GetProofState(), tsb.proofState) } } if ui.Outcome.TrackStatus != outcome.TrackStatus { return fmt.Errorf("track status: %d, expected %d", ui.Outcome.TrackStatus, outcome.TrackStatus) } if ui.Outcome.NumTrackFailures != outcome.NumTrackFailures { return fmt.Errorf("num track failures: %d, expected %d", ui.Outcome.NumTrackFailures, outcome.NumTrackFailures) } if ui.Outcome.NumTrackChanges != outcome.NumTrackChanges { return fmt.Errorf("num track changes: %d, expected %d", ui.Outcome.NumTrackChanges, outcome.NumTrackChanges) } if ui.Outcome.NumProofFailures != outcome.NumProofFailures { return fmt.Errorf("num proof failures: %d, expected %d", ui.Outcome.NumProofFailures, outcome.NumProofFailures) } if ui.Outcome.NumProofSuccesses != outcome.NumProofSuccesses { return fmt.Errorf("num proof successes: %d, expected %d", ui.Outcome.NumProofSuccesses, outcome.NumProofSuccesses) } if ui.Outcome.NumRevoked != outcome.NumRevoked { return fmt.Errorf("num revoked: %d, expected %d", ui.Outcome.NumRevoked, outcome.NumRevoked) } return nil } type byID []*libkb.ServiceBlock func (b byID) Len() int { return len(b) } func (b byID) Less(x, y int) bool { return b[x].ToIDString() < b[y].ToIDString() } func (b byID) Swap(x, y int) { b[x], b[y] = b[y], b[x] } type sbtest struct { name string blocks []sb outcome keybase1.IdentifyOutcome } // these aren't that interesting since all the proof states are // the same, but it does some basic testing of the service blocks // in a TrackChainLink. var sbtests = []sbtest{ { name: "t_alice", blocks: []sb{ {social: true, id: "kbtester2@github", proofState: keybase1.ProofState_OK}, {social: true, id: "tacovontaco@twitter", proofState: keybase1.ProofState_OK}, }, outcome: keybase1.IdentifyOutcome{ NumProofSuccesses: 2, TrackStatus: keybase1.TrackStatus_NEW_OK, }, }, { name: "t_bob", blocks: []sb{ {social: true, id: "kbtester1@github", proofState: keybase1.ProofState_OK}, {social: true, id: "kbtester1@twitter", proofState: keybase1.ProofState_OK}, }, outcome: keybase1.IdentifyOutcome{ NumProofSuccesses: 2, TrackStatus: keybase1.TrackStatus_NEW_OK, }, }, { name: "t_charlie", blocks: []sb{ {social: true, id: "tacoplusplus@github", proofState: keybase1.ProofState_OK}, {social: true, id: "tacovontaco@twitter", proofState: keybase1.ProofState_OK}, }, outcome: keybase1.IdentifyOutcome{ NumProofSuccesses: 2, TrackStatus: keybase1.TrackStatus_NEW_OK, }, }, { name: "t_doug", outcome: keybase1.IdentifyOutcome{ TrackStatus: keybase1.TrackStatus_NEW_ZERO_PROOFS, }, }, } func TestTrackProofServiceBlocks(t *testing.T) { tc := SetupEngineTest(t, "track") defer tc.Cleanup() sigVersion := libkb.GetDefaultSigVersion(tc.G) fu := CreateAndSignupFakeUser(tc, "track") for _, test := range sbtests { err := checkTrack(tc, fu, test.name, test.blocks, &test.outcome, sigVersion) require.NoError(t, err) err = runUntrack(tc, fu, test.name, sigVersion) require.NoError(t, err) } } // track a user that has no proofs func TestTrackProofZero(t *testing.T) { doWithSigChainVersions(func(sigVersion libkb.SigVersion) { _testTrackProofZero(t, sigVersion) }) } func _testTrackProofZero(t *testing.T, sigVersion libkb.SigVersion) { tc := SetupEngineTest(t, "track") defer tc.Cleanup() // create a user with no proofs proofUser := CreateAndSignupFakeUser(tc, "proof") Logout(tc) // create a user to track the proofUser trackUser := CreateAndSignupFakeUser(tc, "track") outcome := keybase1.IdentifyOutcome{ TrackStatus: keybase1.TrackStatus_NEW_ZERO_PROOFS, } err := checkTrack(tc, trackUser, proofUser.Username, nil, &outcome, sigVersion) require.NoError(t, err) } // track a user that has a rooter proof, check the tracking // statement for correctness. func TestTrackProofRooter(t *testing.T) { doWithSigChainVersions(func(sigVersion libkb.SigVersion) { _testTrackProofRooter(t, sigVersion) }) } func _testTrackProofRooter(t *testing.T, sigVersion libkb.SigVersion) { tc := SetupEngineTest(t, "track") defer tc.Cleanup() // create a user with a rooter proof proofUser := CreateAndSignupFakeUser(tc, "proof") _, _, err := proveRooter(tc.G, proofUser, sigVersion) require.NoError(t, err) Logout(tc) // create a user to track the proofUser trackUser := CreateAndSignupFakeUser(tc, "track") rbl := sb{ social: true, id: proofUser.Username + "@rooter", proofState: keybase1.ProofState_OK, } outcome := keybase1.IdentifyOutcome{ NumProofSuccesses: 1, TrackStatus: keybase1.TrackStatus_NEW_OK, } err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion) require.NoError(t, err) // retrack, check the track status outcome.TrackStatus = keybase1.TrackStatus_UPDATE_OK err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion) require.NoError(t, err) } func TestTrackProofGubble(t *testing.T) { tc := SetupEngineTest(t, "track") defer tc.Cleanup() sigVersion := libkb.KeybaseSignatureV2 // create a user with a rooter proof proofUser := CreateAndSignupFakeUser(tc, "proof") proveGubbleSocial(tc, proofUser, sigVersion) proveGubbleCloud(tc, proofUser, sigVersion) Logout(tc) // create a user to track the proofUser trackUser := CreateAndSignupFakeUser(tc, "track") rbl := []sb{ { social: true, id: proofUser.Username + "@gubble.cloud", proofState: keybase1.ProofState_OK, }, { social: true, id: proofUser.Username + "@gubble.social", proofState: keybase1.ProofState_OK, }, } outcome := keybase1.IdentifyOutcome{ NumProofSuccesses: 2, TrackStatus: keybase1.TrackStatus_NEW_OK, } err := checkTrack(tc, trackUser, proofUser.Username, rbl, &outcome, sigVersion) require.NoError(t, err) // retrack, check the track status outcome.TrackStatus = keybase1.TrackStatus_UPDATE_OK err = checkTrack(tc, trackUser, proofUser.Username, rbl, &outcome, sigVersion) require.NoError(t, err) } // upgrade tracking statement when new proof is added: // track a user that has no proofs, then track them again after they add a proof func TestTrackProofUpgrade(t *testing.T) { doWithSigChainVersions(func(sigVersion libkb.SigVersion) { _testTrackProofUpgrade(t, sigVersion) }) } func _testTrackProofUpgrade(t *testing.T, sigVersion libkb.SigVersion) { tc := SetupEngineTest(t, "track") defer tc.Cleanup() // create a user with no proofs proofUser := CreateAndSignupFakeUser(tc, "proof") Logout(tc) // create a user to track the proofUser trackUser := CreateAndSignupFakeUser(tc, "track") outcome := keybase1.IdentifyOutcome{ TrackStatus: keybase1.TrackStatus_NEW_ZERO_PROOFS, } err := checkTrack(tc, trackUser, proofUser.Username, nil, &outcome, sigVersion) require.NoError(t, err) // proofUser adds a rooter proof: Logout(tc) proofUser.LoginOrBust(tc) _, _, err = proveRooter(tc.G, proofUser, sigVersion) require.NoError(t, err) Logout(tc) // trackUser tracks proofUser again: trackUser.LoginOrBust(tc) rbl := sb{ social: true, id: proofUser.Username + "@rooter", proofState: keybase1.ProofState_OK, } outcome = keybase1.IdentifyOutcome{ NumTrackChanges: 1, NumProofSuccesses: 1, TrackStatus: keybase1.TrackStatus_UPDATE_NEW_PROOFS, } err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion) require.NoError(t, err) } // test a change to a proof func TestTrackProofChangeSinceTrack(t *testing.T) { doWithSigChainVersions(func(sigVersion libkb.SigVersion) { _testTrackProofChangeSinceTrack(t, sigVersion) }) } func _testTrackProofChangeSinceTrack(t *testing.T, sigVersion libkb.SigVersion) { tc := SetupEngineTest(t, "track") defer tc.Cleanup() // create a user with a rooter proof proofUser := CreateAndSignupFakeUser(tc, "proof") _, _, err := proveRooter(tc.G, proofUser, sigVersion) require.NoError(t, err) Logout(tc) // create a user to track the proofUser trackUser := CreateAndSignupFakeUser(tc, "track") rbl := sb{ social: true, id: proofUser.Username + "@rooter", proofState: keybase1.ProofState_OK, } outcome := keybase1.IdentifyOutcome{ NumProofSuccesses: 1, TrackStatus: keybase1.TrackStatus_NEW_OK, } err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion) require.NoError(t, err) Logout(tc) // proof user logs in and does a new rooter proof proofUser.LoginOrBust(tc) _, _, err = proveRooter(tc.G, proofUser, sigVersion) require.NoError(t, err) Logout(tc) // track user logs in and tracks proof user again trackUser.LoginOrBust(tc) outcome.TrackStatus = keybase1.TrackStatus_UPDATE_OK err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion) require.NoError(t, err) } // track a user that has a failed rooter proof func TestTrackProofRooterFail(t *testing.T) { doWithSigChainVersions(func(sigVersion libkb.SigVersion) { _testTrackProofRooterFail(t, sigVersion) }) } func _testTrackProofRooterFail(t *testing.T, sigVersion libkb.SigVersion) { tc := SetupEngineTest(t, "track") defer tc.Cleanup() // create a user with a rooter proof proofUser := CreateAndSignupFakeUser(tc, "proof") _, err := proveRooterFail(tc.G, proofUser, sigVersion) require.Error(t, err) Logout(tc) // create a user to track the proofUser trackUser := CreateAndSignupFakeUser(tc, "track") // proveRooterFail posts a bad sig id, so it won't be found. // thus the state is ProofState_SIG_HINT_MISSING rbl := sb{ social: true, id: proofUser.Username + "@rooter", proofState: keybase1.ProofState_SIG_HINT_MISSING, } outcome := keybase1.IdentifyOutcome{ NumProofFailures: 1, TrackStatus: keybase1.TrackStatus_NEW_ZERO_PROOFS, } // and they have no proofs err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion) require.NoError(t, err) } func TestTrackProofGubbleFail(t *testing.T) { tc := SetupEngineTest(t, "track") defer tc.Cleanup() sigVersion := libkb.KeybaseSignatureV2 // create a user with a rooter proof proofUser := CreateAndSignupFakeUser(tc, "proof") proveGubbleSocialFail(tc, proofUser, sigVersion) Logout(tc) // create a user to track the proofUser trackUser := CreateAndSignupFakeUser(tc, "track") // proveGubbleSocialFail posts a bad sig id, so it won't be found. // thus the state is ProofState_SIG_HINT_MISSING rbl := sb{ social: true, id: proofUser.Username + "@gubble.social", proofState: keybase1.ProofState_SIG_HINT_MISSING, } outcome := keybase1.IdentifyOutcome{ NumProofFailures: 1, TrackStatus: keybase1.TrackStatus_NEW_ZERO_PROOFS, } // and they have no proofs err := checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion) require.NoError(t, err) } // track a user that has a rooter proof, remove the proof, then // track again. // Note that the API server won't notice that the rooter proof has // been removed as it only checks every 12 hours. The client will // notice and should generate an appropriate tracking statement. func TestTrackProofRooterRemove(t *testing.T) { doWithSigChainVersions(func(sigVersion libkb.SigVersion) { _testTrackProofRooterRemove(t, sigVersion) }) } func _testTrackProofRooterRemove(t *testing.T, sigVersion libkb.SigVersion) { tc := SetupEngineTest(t, "track") defer tc.Cleanup() // create a user with a rooter proof proofUser := CreateAndSignupFakeUser(tc, "proof") ui, _, err := proveRooter(tc.G, proofUser, sigVersion) require.NoError(t, err) Logout(tc) // create a user to track the proofUser trackUser := CreateAndSignupFakeUser(tc, "track") rbl := sb{ social: true, id: proofUser.Username + "@rooter", proofState: keybase1.ProofState_OK, } outcome := keybase1.IdentifyOutcome{ NumProofSuccesses: 1, TrackStatus: keybase1.TrackStatus_NEW_OK, } err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion) require.NoError(t, err) // remove the rooter proof Logout(tc) proofUser.LoginOrBust(tc) err = proveRooterRemove(tc.G, ui.postID) require.NoError(t, err) Logout(tc) // track again trackUser.LoginOrBust(tc) rbl.proofState = keybase1.ProofState_TEMP_FAILURE outcome = keybase1.IdentifyOutcome{ NumTrackFailures: 1, NumTrackChanges: 1, NumProofFailures: 1, TrackStatus: keybase1.TrackStatus_UPDATE_BROKEN_FAILED_PROOFS, } // use checkTrackForce to skip any proof cache results err = checkTrackForce(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome) require.NoError(t, err) // check that it is "fixed" outcome = keybase1.IdentifyOutcome{ NumProofFailures: 1, TrackStatus: keybase1.TrackStatus_UPDATE_OK, } err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion) require.NoError(t, err) } // test tracking a user who revokes a proof. Revoking a proof // removes it from the sig chain, so this tests the // libkb.IdentifyState.ComputeRevokedProofs() function, and how // libkb.IdentifyOutcome.TrackStatus() interprets the result. func TestTrackProofRooterRevoke(t *testing.T) { doWithSigChainVersions(func(sigVersion libkb.SigVersion) { _testTrackProofRooterRevoke(t, sigVersion) }) } func _testTrackProofRooterRevoke(t *testing.T, sigVersion libkb.SigVersion) { tc := SetupEngineTest(t, "track") defer tc.Cleanup() // create a user with a rooter proof proofUser := CreateAndSignupFakeUser(tc, "proof") _, sigID, err := proveRooter(tc.G, proofUser, sigVersion) require.NoError(t, err) Logout(tc) // create a user to track the proofUser trackUser := CreateAndSignupFakeUser(tc, "track") rbl := sb{ social: true, id: proofUser.Username + "@rooter", proofState: keybase1.ProofState_OK, } outcome := keybase1.IdentifyOutcome{ NumProofSuccesses: 1, TrackStatus: keybase1.TrackStatus_NEW_OK, } err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion) require.NoError(t, err) // revoke the rooter proof Logout(tc) proofUser.LoginOrBust(tc) revEng := NewRevokeSigsEngine(tc.G, []string{sigID.String()}) uis := libkb.UIs{ LogUI: tc.G.UI.GetLogUI(), SecretUI: proofUser.NewSecretUI(), } m := NewMetaContextForTest(tc).WithUIs(uis) err = revEng.Run(m) require.NoError(t, err) Logout(tc) // track proofUser again and check revoked proof handled correctly trackUser.LoginOrBust(tc) outcome = keybase1.IdentifyOutcome{ NumRevoked: 1, TrackStatus: keybase1.TrackStatus_UPDATE_BROKEN_REVOKED, } err = checkTrack(tc, trackUser, proofUser.Username, nil, &outcome, sigVersion) require.NoError(t, err) // track again and check for fix outcome = keybase1.IdentifyOutcome{ TrackStatus: keybase1.TrackStatus_UPDATE_OK, } err = checkTrack(tc, trackUser, proofUser.Username, nil, &outcome, sigVersion) require.NoError(t, err) } // proofUser makes a user@rooter proof, then a user2@rooter proof. // trackUser tracks proofUser. Verify the tracking statement. func TestTrackProofRooterOther(t *testing.T) { tc := SetupEngineTest(t, "track") defer tc.Cleanup() sigVersion := libkb.GetDefaultSigVersion(tc.G) // create a user with a rooter proof proofUser := CreateAndSignupFakeUser(tc, "proof") _, _, err := proveRooter(tc.G, proofUser, sigVersion) require.NoError(t, err) Logout(tc) // post a rooter proof as a different rooter user proofUserOther := CreateAndSignupFakeUser(tc, "proof") Logout(tc) proofUser.LoginOrBust(tc) _, _, err = proveRooterOther(tc.G, proofUser, proofUserOther.Username, sigVersion) require.NoError(t, err) Logout(tc) // create a user to track the proofUser trackUser := CreateAndSignupFakeUser(tc, "track") rbl := sb{ social: true, id: proofUserOther.Username + "@rooter", proofState: keybase1.ProofState_OK, } outcome := keybase1.IdentifyOutcome{ NumProofSuccesses: 1, TrackStatus: keybase1.TrackStatus_NEW_OK, } err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion) require.NoError(t, err) } // proofUser makes a user@rooter proof, trackUser tracks // proofUser. proofUser makes a user2@rooter proof, trackUser // tracks proofUser again. Test that the change is noticed. func TestTrackProofRooterChange(t *testing.T) { tc := SetupEngineTest(t, "track") defer tc.Cleanup() sigVersion := libkb.GetDefaultSigVersion(tc.G) // create a user with a rooter proof proofUser := CreateAndSignupFakeUser(tc, "proof") _, _, err := proveRooter(tc.G, proofUser, sigVersion) require.NoError(t, err) Logout(tc) // create a user to track the proofUser trackUser := CreateAndSignupFakeUser(tc, "track") rbl := sb{ social: true, id: proofUser.Username + "@rooter", proofState: keybase1.ProofState_OK, } outcome := keybase1.IdentifyOutcome{ NumProofSuccesses: 1, TrackStatus: keybase1.TrackStatus_NEW_OK, } err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion) require.NoError(t, err) // post a rooter proof as a different rooter user Logout(tc) proofUserOther := CreateAndSignupFakeUser(tc, "proof") Logout(tc) proofUser.LoginOrBust(tc) _, _, err = proveRooterOther(tc.G, proofUser, proofUserOther.Username, sigVersion) require.NoError(t, err) Logout(tc) // track proofUser again and check new rooter proof with different account handled correctly trackUser.LoginOrBust(tc) rbl.id = proofUserOther.Username + "@rooter" outcome = keybase1.IdentifyOutcome{ NumTrackChanges: 1, NumTrackFailures: 1, NumProofSuccesses: 1, TrackStatus: keybase1.TrackStatus_UPDATE_BROKEN_FAILED_PROOFS, } err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion) require.NoError(t, err) // track again and check for fix outcome = keybase1.IdentifyOutcome{ NumProofSuccesses: 1, TrackStatus: keybase1.TrackStatus_UPDATE_OK, } err = checkTrack(tc, trackUser, proofUser.Username, []sb{rbl}, &outcome, sigVersion) require.NoError(t, err) } // TODO: // * get a test that will generate TrackStatus_NEW_FAIL_PROOFS // (this requires two services, one with an ok proof, one with a // failing proof) // * test upgrade from http to https, or a secure rooter post vs. // regular rooter post to get TrackDiffUpgraded. // * a test that will generate TrackDiffRemoteChanged