github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/chain_link_v2.go (about) 1 package libkb 2 3 import ( 4 "encoding/base64" 5 "errors" 6 "fmt" 7 8 "github.com/keybase/client/go/msgpack" 9 keybase1 "github.com/keybase/client/go/protocol/keybase1" 10 "github.com/keybase/go-codec/codec" 11 ) 12 13 // See comment at top of sig_chain.go for a description of V1, V2 and 14 // V2 stubbed sigchain links. 15 16 type SigchainV2Type int 17 18 // These values must match constants.iced in the proofs library. 19 const ( 20 SigchainV2TypeNone SigchainV2Type = 0 21 SigchainV2TypeEldest SigchainV2Type = 1 22 SigchainV2TypeWebServiceBinding SigchainV2Type = 2 23 SigchainV2TypeTrack SigchainV2Type = 3 24 SigchainV2TypeUntrack SigchainV2Type = 4 25 SigchainV2TypeRevoke SigchainV2Type = 5 26 SigchainV2TypeCryptocurrency SigchainV2Type = 6 27 SigchainV2TypeAnnouncement SigchainV2Type = 7 28 SigchainV2TypeDevice SigchainV2Type = 8 29 SigchainV2TypeWebServiceBindingWithRevoke SigchainV2Type = 9 30 SigchainV2TypeCryptocurrencyWithRevoke SigchainV2Type = 10 31 SigchainV2TypeSibkey SigchainV2Type = 11 32 SigchainV2TypeSubkey SigchainV2Type = 12 33 SigchainV2TypePGPUpdate SigchainV2Type = 13 34 SigchainV2TypePerUserKey SigchainV2Type = 14 35 SigchainV2TypeWalletStellar SigchainV2Type = 15 36 SigchainV2TypeWotVouch SigchainV2Type = 16 37 SigchainV2TypeWotVouchWithRevoke SigchainV2Type = 17 38 SigchainV2TypeWotReact SigchainV2Type = 18 39 40 // Team link types 41 // If you add a new one be sure to get all of these too: 42 // - A corresponding libkb.LinkType in constants.go 43 // - SigchainV2TypeFromV1TypeTeams 44 // - SigChainV2Type.IsSupportedTeamType 45 // - SigChainV2Type.TeamAllowStubWithAdminFlag 46 // - TeamSigChainPlayer.addInnerLink (add a case) 47 SigchainV2TypeTeamRoot SigchainV2Type = 33 48 SigchainV2TypeTeamNewSubteam SigchainV2Type = 34 49 SigchainV2TypeTeamChangeMembership SigchainV2Type = 35 50 SigchainV2TypeTeamRotateKey SigchainV2Type = 36 51 SigchainV2TypeTeamLeave SigchainV2Type = 37 52 SigchainV2TypeTeamSubteamHead SigchainV2Type = 38 53 SigchainV2TypeTeamRenameSubteam SigchainV2Type = 39 54 SigchainV2TypeTeamInvite SigchainV2Type = 40 55 SigchainV2TypeTeamRenameUpPointer SigchainV2Type = 41 56 SigchainV2TypeTeamDeleteRoot SigchainV2Type = 42 57 SigchainV2TypeTeamDeleteSubteam SigchainV2Type = 43 58 SigchainV2TypeTeamDeleteUpPointer SigchainV2Type = 44 59 // Note that 45 is skipped, since it's retired; used to be LegacyTLFUpgrade 60 SigchainV2TypeTeamSettings SigchainV2Type = 46 61 SigchainV2TypeTeamKBFSSettings SigchainV2Type = 47 62 SigchainV2TypeTeamBotSettings SigchainV2Type = 48 63 ) 64 65 // NeedsSignature is untrue of most supported link types. If a link can 66 // be stubbed, that means we potentially won't get to verify its signature, 67 // since we need the full link to verify signatures. However, in some cases, 68 // signature verification is required, and hence stubbing is disallowed. 69 // NOTE when modifying this function ensure that web/sig.iced#_allow_stubbing 70 // is updated as well. 71 func (t SigchainV2Type) AllowStubbing() bool { 72 73 // Unsupported types don't need signatures. Otherwise we can't 74 // make code forwards-compatible. 75 if !t.IsSupportedUserType() { 76 return true 77 } 78 79 // Of known types, Track, Untrack and Announcement can be stubbed, but 80 // nothing else, for now.... 81 switch t { 82 case SigchainV2TypeTrack, SigchainV2TypeUntrack, SigchainV2TypeAnnouncement: 83 return true 84 default: 85 return false 86 } 87 } 88 89 // NOTE when modifying this function ensure that web/sig.iced#_is_supported_user_type 90 // is updated as well. 91 func (t SigchainV2Type) IsSupportedUserType() bool { 92 switch t { 93 case SigchainV2TypeNone, 94 SigchainV2TypeEldest, 95 SigchainV2TypeWebServiceBinding, 96 SigchainV2TypeTrack, 97 SigchainV2TypeUntrack, 98 SigchainV2TypeRevoke, 99 SigchainV2TypeCryptocurrency, 100 SigchainV2TypeAnnouncement, 101 SigchainV2TypeDevice, 102 SigchainV2TypeWebServiceBindingWithRevoke, 103 SigchainV2TypeCryptocurrencyWithRevoke, 104 SigchainV2TypeSibkey, 105 SigchainV2TypeSubkey, 106 SigchainV2TypePGPUpdate, 107 SigchainV2TypePerUserKey, 108 SigchainV2TypeWotVouchWithRevoke, 109 SigchainV2TypeWalletStellar: 110 return true 111 default: 112 return false 113 } 114 } 115 116 func (t SigchainV2Type) IsSupportedType() bool { 117 return t.IsSupportedTeamType() || t.IsSupportedUserType() 118 } 119 120 // Whether a type is for team sigchains. 121 // Also the list of which types are supported by this client. 122 func (t SigchainV2Type) IsSupportedTeamType() bool { 123 switch t { 124 case SigchainV2TypeTeamRoot, 125 SigchainV2TypeTeamNewSubteam, 126 SigchainV2TypeTeamChangeMembership, 127 SigchainV2TypeTeamRotateKey, 128 SigchainV2TypeTeamLeave, 129 SigchainV2TypeTeamSubteamHead, 130 SigchainV2TypeTeamRenameSubteam, 131 SigchainV2TypeTeamInvite, 132 SigchainV2TypeTeamRenameUpPointer, 133 SigchainV2TypeTeamDeleteRoot, 134 SigchainV2TypeTeamDeleteSubteam, 135 SigchainV2TypeTeamDeleteUpPointer, 136 SigchainV2TypeTeamKBFSSettings, 137 SigchainV2TypeTeamSettings, 138 SigchainV2TypeTeamBotSettings: 139 return true 140 default: 141 return false 142 } 143 } 144 145 func (t SigchainV2Type) RequiresAtLeastRole() keybase1.TeamRole { 146 if !t.IsSupportedTeamType() { 147 // Links from the future require a bare minimum. 148 // They should be checked later by a code update that busts the cache. 149 return keybase1.TeamRole_RESTRICTEDBOT 150 } 151 switch t { 152 case SigchainV2TypeTeamLeave: 153 return keybase1.TeamRole_RESTRICTEDBOT 154 case SigchainV2TypeTeamRoot: 155 return keybase1.TeamRole_BOT 156 case SigchainV2TypeTeamRotateKey, 157 SigchainV2TypeTeamKBFSSettings: 158 return keybase1.TeamRole_WRITER 159 default: 160 return keybase1.TeamRole_ADMIN 161 } 162 } 163 164 func (t SigchainV2Type) TeamAllowStubWithAdminFlag(isAdmin bool) bool { 165 if isAdmin { 166 // Links cannot be stubbed for owners and admins 167 return false 168 } 169 switch t { 170 case SigchainV2TypeTeamNewSubteam, 171 SigchainV2TypeTeamRenameSubteam, 172 SigchainV2TypeTeamDeleteSubteam, 173 SigchainV2TypeTeamInvite, 174 SigchainV2TypeTeamSettings, 175 SigchainV2TypeTeamKBFSSettings, 176 SigchainV2TypeTeamBotSettings: 177 return true 178 default: 179 // Disallow stubbing of other known links. 180 // Allow stubbing of unknown link types for forward compatibility. 181 return !t.IsSupportedTeamType() 182 } 183 } 184 185 type OuterLinkV2Partial0 struct { 186 _struct bool `codec:",toarray"` //nolint 187 Version SigVersion `codec:"version"` 188 Seqno keybase1.Seqno `codec:"seqno"` 189 Prev LinkID `codec:"prev"` 190 Curr LinkID `codec:"curr"` 191 LinkType SigchainV2Type `codec:"type"` 192 } 193 194 type OuterLinkV2Partial1 struct { 195 _struct bool `codec:",toarray"` //nolint 196 Version SigVersion `codec:"version"` 197 Seqno keybase1.Seqno `codec:"seqno"` 198 Prev LinkID `codec:"prev"` 199 Curr LinkID `codec:"curr"` 200 LinkType SigchainV2Type `codec:"type"` 201 SeqType keybase1.SeqType `codec:"seqtype"` 202 } 203 204 type OuterLinkV2Partial2 struct { 205 _struct bool `codec:",toarray"` //nolint 206 Version SigVersion `codec:"version"` 207 Seqno keybase1.Seqno `codec:"seqno"` 208 Prev LinkID `codec:"prev"` 209 Curr LinkID `codec:"curr"` 210 LinkType SigchainV2Type `codec:"type"` 211 SeqType keybase1.SeqType `codec:"seqtype"` 212 IgnoreIfUnsupported SigIgnoreIfUnsupported `codec:"ignore_if_unsupported"` 213 } 214 215 // OuterLinkV2 is the second version of Keybase sigchain signatures. 216 type OuterLinkV2 struct { 217 _struct bool `codec:",toarray"` //nolint 218 Version SigVersion `codec:"version"` 219 Seqno keybase1.Seqno `codec:"seqno"` 220 Prev LinkID `codec:"prev"` 221 Curr LinkID `codec:"curr"` 222 LinkType SigchainV2Type `codec:"type"` 223 // -- Links exist in the wild that are missing fields below this line (see Partial0) 224 SeqType keybase1.SeqType `codec:"seqtype"` 225 // -- Links exist in the wild that are missing fields below this line too (see Partial1) 226 // Whether the link can be ignored by clients that do not support its link type. 227 // This does _not_ mean the link can be ignored if the client supports the link type. 228 // When it comes to stubbing, if the link is unsupported and this bit is set then 229 // - it can be stubbed for non-admins 230 // - it cannot be stubbed for admins 231 IgnoreIfUnsupported SigIgnoreIfUnsupported `codec:"ignore_if_unsupported"` 232 // -- Links exist in the wild that are missing fields below this line too (see Partial2) 233 // If not provided, both of these are nil, and highSkip in the inner link is set to nil. 234 // Note that a link providing HighSkipSeqno == 0 and HighSkipHash == nil is valid 235 // (and mandatory) for an initial link. 236 HighSkipSeqno *keybase1.Seqno `codec:"high_skip_seqno"` 237 HighSkipHash *LinkID `codec:"high_skip_hash"` 238 } 239 240 func (o OuterLinkV2) Encode() ([]byte, error) { 241 return msgpack.Encode(o) 242 } 243 244 type OuterLinkV2WithMetadata struct { 245 OuterLinkV2 246 raw []byte 247 sigID keybase1.SigID 248 sig string 249 kid keybase1.KID 250 } 251 252 // An OuterLinkV2WithMetadata should never be encoded/decoded 253 // directly. This is to avoid problems like 254 // https://github.com/keybase/saltpack/pull/43 . 255 256 var _ codec.Selfer = (*OuterLinkV2WithMetadata)(nil) 257 258 var errCodecEncodeSelf = errors.New("Unexpected call to OuterLinkV2WithMetadata.CodecEncodeSelf") 259 var errCodecDecodeSelf = errors.New("Unexpected call to OuterLinkV2WithMetadata.CodecDecodeSelf") 260 261 func (o *OuterLinkV2WithMetadata) CodecEncodeSelf(e *codec.Encoder) { 262 panic(errCodecEncodeSelf) 263 } 264 265 func (o *OuterLinkV2WithMetadata) CodecDecodeSelf(d *codec.Decoder) { 266 panic(errCodecDecodeSelf) 267 } 268 269 type SigIgnoreIfUnsupported bool 270 type SigHasRevokes bool 271 272 func (b SigIgnoreIfUnsupported) Bool() bool { return bool(b) } 273 274 func encodeOuterLink( 275 m MetaContext, 276 v1LinkType LinkType, 277 seqno keybase1.Seqno, 278 innerLinkJSON []byte, 279 prevLinkID LinkID, 280 hasRevokes SigHasRevokes, 281 seqType keybase1.SeqType, 282 ignoreIfUnsupported SigIgnoreIfUnsupported, 283 highSkip *HighSkip, 284 ) ([]byte, error) { 285 var encodedOuterLink []byte 286 287 currLinkID := ComputeLinkID(innerLinkJSON) 288 289 v2LinkType, err := SigchainV2TypeFromV1TypeAndRevocations(string(v1LinkType), hasRevokes, ignoreIfUnsupported) 290 if err != nil { 291 return encodedOuterLink, err 292 } 293 294 // When 2.3 links are mandatory, it will be invalid for highSkip == nil, 295 // so the featureflag check will be removed and the nil check will result 296 // in an error. 297 allowHighSkips := m.G().Env.GetFeatureFlags().HasFeature(EnvironmentFeatureAllowHighSkips) 298 var highSkipSeqno *keybase1.Seqno 299 var highSkipHash *LinkID 300 if highSkip != nil && allowHighSkips { 301 highSkipSeqno = &highSkip.Seqno 302 highSkipHash = &highSkip.Hash 303 } 304 return encodeOuterLinkWithLinkID(v2LinkType, seqno, currLinkID, prevLinkID, seqType, ignoreIfUnsupported, highSkipSeqno, highSkipHash) 305 } 306 307 func encodeOuterLinkWithLinkID( 308 v2LinkType SigchainV2Type, 309 seqno keybase1.Seqno, 310 currLinkID LinkID, 311 prevLinkID LinkID, 312 seqType keybase1.SeqType, 313 ignoreIfUnsupported SigIgnoreIfUnsupported, 314 highSkipSeqno *keybase1.Seqno, 315 highSkipHash *LinkID, 316 ) ([]byte, error) { 317 318 var encodedOuterLink []byte 319 var err error 320 321 if highSkipSeqno != nil && highSkipHash != nil { 322 outerLink := OuterLinkV2{ 323 Version: 2, 324 Seqno: seqno, 325 Prev: prevLinkID, 326 Curr: currLinkID, 327 LinkType: v2LinkType, 328 SeqType: seqType, 329 IgnoreIfUnsupported: ignoreIfUnsupported, 330 HighSkipSeqno: highSkipSeqno, 331 HighSkipHash: highSkipHash, 332 } 333 encodedOuterLink, err = outerLink.Encode() 334 } else { 335 // This is a helper struct. When the code for Sigchain 2.3 336 // is released, it is possible some clients will still post 2.2 337 // links, i.e., without high_skip information. Due to a bug 338 // in Keybase's fork of go-codec, omitempty does not work 339 // for arrays. So, we send up the serialization of the 340 // appropriate struct depending on whether we are making a 2.3 link. 341 // When 2.3 links are mandatory, this struct can be deleted. 342 encodedOuterLink, err = msgpack.Encode(OuterLinkV2Partial2{ 343 Version: 2, 344 Seqno: seqno, 345 Prev: prevLinkID, 346 Curr: currLinkID, 347 LinkType: v2LinkType, 348 SeqType: seqType, 349 IgnoreIfUnsupported: ignoreIfUnsupported, 350 }) 351 } 352 353 if err != nil { 354 return encodedOuterLink, err 355 } 356 357 return encodedOuterLink, err 358 } 359 360 func MakeSigchainV2OuterSig( 361 m MetaContext, 362 signingKey GenericKey, 363 v1LinkType LinkType, 364 seqno keybase1.Seqno, 365 innerLinkJSON []byte, 366 prevLinkID LinkID, 367 hasRevokes SigHasRevokes, 368 seqType keybase1.SeqType, 369 ignoreIfUnsupported SigIgnoreIfUnsupported, 370 highSkip *HighSkip, 371 ) (sig string, sigid keybase1.SigID, linkID LinkID, err error) { 372 373 encodedOuterLink, err := encodeOuterLink(m, v1LinkType, seqno, innerLinkJSON, prevLinkID, hasRevokes, seqType, ignoreIfUnsupported, highSkip) 374 if err != nil { 375 return sig, sigid, linkID, err 376 } 377 var sigIDBase keybase1.SigIDBase 378 379 sig, sigIDBase, err = signingKey.SignToString(encodedOuterLink) 380 if err != nil { 381 return sig, sigid, linkID, err 382 } 383 params := keybase1.SigIDSuffixParametersFromTypeAndVersion(string(v1LinkType), keybase1.SigVersion(2)) 384 sigid = sigIDBase.ToSigID(params) 385 386 linkID = ComputeLinkID(encodedOuterLink) 387 return sig, sigid, linkID, nil 388 } 389 390 func (o OuterLinkV2) EncodeTruncateHighSkips() ([]byte, error) { 391 return encodeOuterLinkWithLinkID(o.LinkType, o.Seqno, o.Curr, o.Prev, o.SeqType, o.IgnoreIfUnsupported, o.HighSkipSeqno, o.HighSkipHash) 392 } 393 394 func (o OuterLinkV2) EncodePartial(numFields int) ([]byte, error) { 395 switch numFields { 396 case 5: 397 return msgpack.Encode(OuterLinkV2Partial0{ 398 Version: 2, 399 Seqno: o.Seqno, 400 Prev: o.Prev, 401 Curr: o.Curr, 402 LinkType: o.LinkType, 403 }) 404 case 6: 405 return msgpack.Encode(OuterLinkV2Partial1{ 406 Version: 2, 407 Seqno: o.Seqno, 408 Prev: o.Prev, 409 Curr: o.Curr, 410 LinkType: o.LinkType, 411 SeqType: o.SeqType, 412 }) 413 case 7: 414 return msgpack.Encode(OuterLinkV2Partial2{ 415 Version: 2, 416 Seqno: o.Seqno, 417 Prev: o.Prev, 418 Curr: o.Curr, 419 LinkType: o.LinkType, 420 SeqType: o.SeqType, 421 IgnoreIfUnsupported: o.IgnoreIfUnsupported, 422 }) 423 case 9: 424 return msgpack.Encode(OuterLinkV2{ 425 Version: 2, 426 Seqno: o.Seqno, 427 Prev: o.Prev, 428 Curr: o.Curr, 429 LinkType: o.LinkType, 430 SeqType: o.SeqType, 431 IgnoreIfUnsupported: o.IgnoreIfUnsupported, 432 HighSkipHash: o.HighSkipHash, 433 HighSkipSeqno: o.HighSkipSeqno, 434 }) 435 default: 436 return nil, fmt.Errorf("Cannot encode sig2 partial with %d fields", numFields) 437 } 438 439 } 440 441 func DecodeStubbedOuterLinkV2(b64encoded string) (*OuterLinkV2WithMetadata, error) { 442 payload, err := base64.StdEncoding.DecodeString(b64encoded) 443 if err != nil { 444 return nil, err 445 } 446 if !msgpack.IsEncodedMsgpackArray(payload) { 447 return nil, ChainLinkError{"expected a msgpack array but got leading junk"} 448 } 449 var ol OuterLinkV2 450 if err = msgpack.Decode(&ol, payload); err != nil { 451 return nil, err 452 } 453 return &OuterLinkV2WithMetadata{OuterLinkV2: ol, raw: payload}, nil 454 } 455 456 func (o OuterLinkV2WithMetadata) EncodeStubbed() string { 457 return base64.StdEncoding.EncodeToString(o.raw) 458 } 459 460 func (o OuterLinkV2WithMetadata) LinkID() LinkID { 461 return ComputeLinkID(o.raw) 462 } 463 464 func (o OuterLinkV2WithMetadata) SigID() keybase1.SigID { 465 return o.sigID 466 } 467 468 func (o OuterLinkV2WithMetadata) Raw() []byte { 469 return o.raw 470 } 471 472 func (o OuterLinkV2WithMetadata) Verify(ctx VerifyContext) (kid keybase1.KID, err error) { 473 key, err := ImportKeypairFromKID(o.kid) 474 if err != nil { 475 return kid, err 476 } 477 _, err = key.VerifyString(ctx, o.sig, o.raw) 478 if err != nil { 479 return kid, err 480 } 481 return o.kid, nil 482 } 483 484 func (t SigchainV2Type) SigIDSuffixParams(v keybase1.SigVersion) keybase1.SigIDSuffixParameters { 485 return keybase1.SigIDSuffixParameters{ 486 IsUserSig: t.IsSupportedUserType(), 487 IsWalletStellar: (t == SigchainV2TypeWalletStellar), 488 SigVersion: v, 489 } 490 } 491 492 func DecodeOuterLinkV2(armored string) (*OuterLinkV2WithMetadata, error) { 493 payload, kid, sigIDBase, err := SigExtractPayloadAndKID(armored) 494 if err != nil { 495 return nil, err 496 } 497 if !msgpack.IsEncodedMsgpackArray(payload) { 498 return nil, ChainLinkError{"expected a msgpack array but got leading junk"} 499 } 500 501 var ol OuterLinkV2 502 if err := msgpack.Decode(&ol, payload); err != nil { 503 return nil, err 504 } 505 params := ol.LinkType.SigIDSuffixParams(keybase1.SigVersion(2)) 506 ret := OuterLinkV2WithMetadata{ 507 OuterLinkV2: ol, 508 sigID: sigIDBase.ToSigID(params), 509 raw: payload, 510 kid: kid, 511 sig: armored, 512 } 513 return &ret, nil 514 } 515 516 func SigchainV2TypeFromV1TypeAndRevocations(s string, hasRevocations SigHasRevokes, ignoreIfUnsupported SigIgnoreIfUnsupported) (ret SigchainV2Type, err error) { 517 518 switch s { 519 case "eldest": 520 ret = SigchainV2TypeEldest 521 case "web_service_binding": 522 if hasRevocations { 523 ret = SigchainV2TypeWebServiceBindingWithRevoke 524 } else { 525 ret = SigchainV2TypeWebServiceBinding 526 } 527 case "track": 528 ret = SigchainV2TypeTrack 529 case "untrack": 530 ret = SigchainV2TypeUntrack 531 case "revoke": 532 ret = SigchainV2TypeRevoke 533 case "cryptocurrency": 534 if hasRevocations { 535 ret = SigchainV2TypeCryptocurrencyWithRevoke 536 } else { 537 ret = SigchainV2TypeCryptocurrency 538 } 539 case "announcement": 540 ret = SigchainV2TypeAnnouncement 541 case "device": 542 ret = SigchainV2TypeDevice 543 case "sibkey": 544 ret = SigchainV2TypeSibkey 545 case "subkey": 546 ret = SigchainV2TypeSubkey 547 case "pgp_update": 548 ret = SigchainV2TypePGPUpdate 549 case "per_user_key": 550 ret = SigchainV2TypePerUserKey 551 case string(LinkTypeWalletStellar): 552 ret = SigchainV2TypeWalletStellar 553 case string(LinkTypeWotVouch): 554 if hasRevocations { 555 ret = SigchainV2TypeWotVouchWithRevoke 556 } else { 557 ret = SigchainV2TypeWotVouch 558 } 559 case string(LinkTypeWotReact): 560 ret = SigchainV2TypeWotReact 561 default: 562 teamRes, teamErr := SigchainV2TypeFromV1TypeTeams(s) 563 if teamErr == nil { 564 ret = teamRes 565 } else { 566 ret = SigchainV2TypeNone 567 if !ignoreIfUnsupported { 568 err = ChainLinkError{fmt.Sprintf("Unknown sig v1 type: %s", s)} 569 } 570 } 571 } 572 573 if ret.AllowStubbing() && bool(hasRevocations) { 574 err = ChainLinkError{fmt.Sprintf("invalid chain link of type %d with a revocation", ret)} 575 } 576 577 return ret, err 578 } 579 580 func SigchainV2TypeFromV1TypeTeams(s string) (ret SigchainV2Type, err error) { 581 switch LinkType(s) { 582 case LinkTypeTeamRoot: 583 ret = SigchainV2TypeTeamRoot 584 case LinkTypeNewSubteam: 585 ret = SigchainV2TypeTeamNewSubteam 586 case LinkTypeChangeMembership: 587 ret = SigchainV2TypeTeamChangeMembership 588 case LinkTypeRotateKey: 589 ret = SigchainV2TypeTeamRotateKey 590 case LinkTypeLeave: 591 ret = SigchainV2TypeTeamLeave 592 case LinkTypeSubteamHead: 593 ret = SigchainV2TypeTeamSubteamHead 594 case LinkTypeRenameSubteam: 595 ret = SigchainV2TypeTeamRenameSubteam 596 case LinkTypeInvite: 597 ret = SigchainV2TypeTeamInvite 598 case LinkTypeRenameUpPointer: 599 ret = SigchainV2TypeTeamRenameUpPointer 600 case LinkTypeDeleteRoot: 601 ret = SigchainV2TypeTeamDeleteRoot 602 case LinkTypeDeleteSubteam: 603 ret = SigchainV2TypeTeamDeleteSubteam 604 case LinkTypeDeleteUpPointer: 605 ret = SigchainV2TypeTeamDeleteUpPointer 606 case LinkTypeKBFSSettings: 607 ret = SigchainV2TypeTeamKBFSSettings 608 case LinkTypeSettings: 609 ret = SigchainV2TypeTeamSettings 610 case LinkTypeTeamBotSettings: 611 ret = SigchainV2TypeTeamBotSettings 612 default: 613 return SigchainV2TypeNone, ChainLinkError{fmt.Sprintf("Unknown team sig v1 type: %s", s)} 614 } 615 616 return ret, err 617 } 618 619 func mismatchError(format string, arg ...interface{}) error { 620 return SigchainV2MismatchedFieldError{fmt.Sprintf(format, arg...)} 621 } 622 623 func (o OuterLinkV2) AssertFields( 624 version SigVersion, 625 seqno keybase1.Seqno, 626 prev LinkID, 627 curr LinkID, 628 linkType SigchainV2Type, 629 seqType keybase1.SeqType, 630 ignoreIfUnsupported SigIgnoreIfUnsupported, 631 highSkip *HighSkip, 632 ) (err error) { 633 if o.Version != version { 634 return mismatchError("version field (%d != %d)", o.Version, version) 635 } 636 if o.Seqno != seqno { 637 return mismatchError("seqno field: (%d != %d)", o.Seqno, seqno) 638 } 639 if !o.Prev.Eq(prev) { 640 return mismatchError("prev pointer: (%s != !%s)", o.Prev, prev) 641 } 642 if !o.Curr.Eq(curr) { 643 return mismatchError("curr pointer: (%s != %s)", o.Curr, curr) 644 } 645 if !(linkType == SigchainV2TypeNone && ignoreIfUnsupported) && o.LinkType != linkType { 646 return mismatchError("link type: (%d != %d)", o.LinkType, linkType) 647 } 648 if o.SeqType != seqType { 649 return mismatchError("seq type: (%d != %d)", o.SeqType, seqType) 650 } 651 if o.IgnoreIfUnsupported != ignoreIfUnsupported { 652 return mismatchError("ignore_if_unsupported: (%v != %v)", o.IgnoreIfUnsupported, ignoreIfUnsupported) 653 } 654 655 err = o.assertHighSkip(highSkip) 656 if err != nil { 657 return err 658 } 659 660 return nil 661 } 662 663 func (o OuterLinkV2) assertHighSkip(highSkip *HighSkip) error { 664 if highSkip == nil && o.HighSkipSeqno != nil { 665 return mismatchError("provided HighSkipSeqno (%d) in outer link but not in inner link", o.HighSkipSeqno) 666 } 667 if highSkip == nil && o.HighSkipHash != nil { 668 return mismatchError("provided HighSkipHash (%v) in outer link but not in inner link", o.HighSkipHash) 669 } 670 671 // o.HighSkipHash may be nil even if highSkip is not, so we don't check it 672 if highSkip != nil && o.HighSkipSeqno == nil { 673 return mismatchError("provided HighSkip in inner link but not HighSkipSeqno in outer link") 674 } 675 676 if highSkip == nil { 677 return nil 678 } 679 680 if *o.HighSkipSeqno != highSkip.Seqno { 681 return mismatchError("highSkip.Seqno field outer (%d)/inner (%d) mismatch", *o.HighSkipSeqno, highSkip.Seqno) 682 } 683 684 if o.HighSkipHash == nil && highSkip.Hash != nil { 685 return mismatchError("Provided HighSkip.Hash in outer link but not inner.") 686 } 687 if o.HighSkipHash != nil && highSkip.Hash == nil { 688 return mismatchError("Provided HighSkip.Hash in inner link but not outer.") 689 } 690 691 if o.HighSkipHash != nil && !o.HighSkipHash.Eq(highSkip.Hash) { 692 return mismatchError("highSkip.Hash field outer (%v)/inner (%v) mismatch", o.HighSkipHash, highSkip.Hash) 693 } 694 695 return nil 696 } 697 698 func (o OuterLinkV2) AssertSomeFields( 699 version SigVersion, 700 seqno keybase1.Seqno, 701 ) (err error) { 702 if o.Version != version { 703 return mismatchError("version field (%d != %d)", o.Version, version) 704 } 705 if o.Seqno != seqno { 706 return mismatchError("seqno field: (%d != %d)", o.Seqno, seqno) 707 } 708 return nil 709 }