github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/teams/create.go (about) 1 package teams 2 3 import ( 4 "errors" 5 "fmt" 6 7 "golang.org/x/net/context" 8 9 "github.com/keybase/client/go/engine" 10 "github.com/keybase/client/go/libkb" 11 "github.com/keybase/client/go/protocol/keybase1" 12 "github.com/keybase/client/go/teams/hidden" 13 jsonw "github.com/keybase/go-jsonw" 14 ) 15 16 func CreateImplicitTeam(ctx context.Context, g *libkb.GlobalContext, impTeam keybase1.ImplicitTeamDisplayName) (res keybase1.TeamID, teamName keybase1.TeamName, err error) { 17 defer g.CTrace(ctx, "CreateImplicitTeam", &err)() 18 19 teamName, err = NewImplicitTeamName() 20 if err != nil { 21 return res, teamName, err 22 } 23 teamID := teamName.ToTeamID(impTeam.IsPublic) 24 25 merkleRoot, err := g.MerkleClient.FetchRootFromServer(libkb.NewMetaContext(ctx, g), libkb.TeamMerkleFreshnessForAdmin) 26 if err != nil { 27 return res, teamName, err 28 } 29 30 perUserKeyUpgradeSoft(ctx, g, "create-implicit-team") 31 32 me, err := loadMeForSignatures(ctx, g) 33 if err != nil { 34 return res, teamName, err 35 } 36 37 // Load all the Keybase users 38 loadUsernameList := func(usernames []string) (res []*keybase1.UserPlusKeysV2, err error) { 39 for _, username := range usernames { 40 arg := libkb.NewLoadUserArg(g).WithName(username).WithNetContext(ctx).WithPublicKeyOptional() 41 upak, _, err := g.GetUPAKLoader().LoadV2(arg) 42 if err != nil { 43 g.Log.CDebugf(ctx, "CreateImplicitTeam: failed to load user: %s msg: %s", username, err) 44 return res, err 45 } 46 res = append(res, &upak.Current) 47 } 48 return res, nil 49 } 50 51 ownerUPAKs, err := loadUsernameList(impTeam.Writers.KeybaseUsers) 52 if err != nil { 53 return res, teamName, err 54 } 55 readerUPAKs, err := loadUsernameList(impTeam.Readers.KeybaseUsers) 56 if err != nil { 57 return res, teamName, err 58 } 59 60 var owners []SCTeamMember 61 var readers []SCTeamMember 62 var ownerInvites []SCTeamInvite 63 var readerInvites []SCTeamInvite 64 65 // Form secret boxes and make invites for KB users with no PUKs 66 secretboxRecipients := make(map[keybase1.UserVersion]keybase1.PerUserKey) 67 68 // Form secret boxes for KB users with PUKs, and invites for those without 69 for _, upak := range ownerUPAKs { 70 uv := upak.ToUserVersion() 71 puk := upak.GetLatestPerUserKey() 72 if puk == nil { 73 // Add this person as an invite if they do not have a puk 74 ownerInvites = append(ownerInvites, SCTeamInvite{ 75 Type: "keybase", 76 Name: uv.TeamInviteName(), 77 ID: NewInviteID(), 78 }) 79 } else { 80 secretboxRecipients[uv] = *puk 81 owners = append(owners, SCTeamMember(uv)) 82 } 83 } 84 for _, upak := range readerUPAKs { 85 uv := upak.ToUserVersion() 86 puk := upak.GetLatestPerUserKey() 87 if puk == nil { 88 // Add this person as an invite if they do not have a puk 89 readerInvites = append(readerInvites, SCTeamInvite{ 90 Type: "keybase", 91 Name: uv.TeamInviteName(), 92 ID: NewInviteID(), 93 }) 94 } else { 95 secretboxRecipients[uv] = *puk 96 readers = append(readers, SCTeamMember(uv)) 97 } 98 } 99 100 members := SCTeamMembers{ 101 Owners: &[]SCTeamMember{}, 102 Admins: &[]SCTeamMember{}, 103 Writers: &[]SCTeamMember{}, 104 Readers: &[]SCTeamMember{}, 105 Bots: &[]SCTeamMember{}, 106 RestrictedBots: &[]SCTeamMember{}, 107 } 108 if len(owners) > 0 { 109 members.Owners = &owners 110 } 111 if len(readers) > 0 { 112 members.Readers = &readers 113 } 114 115 // Add invites for assertions 116 for _, assertion := range impTeam.Writers.UnresolvedUsers { 117 ownerInvites = append(ownerInvites, SCTeamInvite{ 118 Type: assertion.TeamInviteType(), 119 Name: assertion.TeamInviteName(), 120 ID: NewInviteID(), 121 }) 122 } 123 124 for _, assertion := range impTeam.Readers.UnresolvedUsers { 125 readerInvites = append(readerInvites, SCTeamInvite{ 126 Type: assertion.TeamInviteType(), 127 Name: assertion.TeamInviteName(), 128 ID: NewInviteID(), 129 }) 130 } 131 132 invites := &SCTeamInvites{ 133 Owners: nil, 134 Admins: nil, 135 Writers: nil, 136 Readers: nil, 137 } 138 if len(ownerInvites) > 0 { 139 invites.Owners = &ownerInvites 140 } 141 if len(readerInvites) > 0 { 142 invites.Readers = &readerInvites 143 } 144 145 // Post the team 146 return teamID, teamName, 147 makeSigAndPostRootTeam(ctx, g, me, members, invites, secretboxRecipients, teamName.String(), 148 teamID, impTeam.IsPublic, true, nil, *merkleRoot) 149 } 150 151 func makeSigAndPostRootTeam(ctx context.Context, g *libkb.GlobalContext, me libkb.UserForSignatures, members SCTeamMembers, 152 invites *SCTeamInvites, secretboxRecipients map[keybase1.UserVersion]keybase1.PerUserKey, name string, 153 teamID keybase1.TeamID, public, implicit bool, settings *SCTeamSettings, merkleRoot libkb.MerkleRoot) (err error) { 154 mctx := libkb.NewMetaContext(ctx, g) 155 defer g.Trace("makeSigAndPostRootTeam", &err)() 156 mctx.Debug("makeSigAndPostRootTeam get device keys") 157 deviceSigningKey, err := mctx.G().ActiveDevice.SigningKey() 158 if err != nil { 159 return err 160 } 161 deviceEncryptionKey, err := mctx.G().ActiveDevice.EncryptionKey() 162 if err != nil { 163 return err 164 } 165 166 // These boxes will get posted along with the sig below. 167 m, err := NewTeamKeyManager(mctx.G(), teamID) 168 if err != nil { 169 return err 170 } 171 secretboxes, err := m.SharedSecretBoxes(mctx, deviceEncryptionKey, secretboxRecipients) 172 if err != nil { 173 return err 174 } 175 176 perTeamSigningKey, err := m.SigningKey() 177 if err != nil { 178 return err 179 } 180 perTeamEncryptionKey, err := m.EncryptionKey() 181 if err != nil { 182 return err 183 } 184 185 mctx.Debug("makeSigAndPostRootTeam make sigs") 186 teamSection, err := makeRootTeamSection(name, teamID, members, invites, perTeamSigningKey.GetKID(), 187 perTeamEncryptionKey.GetKID(), public, implicit, settings) 188 if err != nil { 189 return err 190 } 191 192 err = addSummaryHash(&teamSection, secretboxes) 193 if err != nil { 194 return err 195 } 196 197 // At this point the team section has every field filled out except the 198 // reverse sig. Now we'll wrap it into a full sig, marshal it to JSON, and 199 // sign it, *twice*. The first time with the per-team signing key, to 200 // produce the reverse sig, and the second time with the device signing 201 // key, after the reverse sig has been written in. 202 sigBodyBeforeReverse, err := TeamRootSig(g, me, deviceSigningKey, teamSection, merkleRoot) 203 if err != nil { 204 return err 205 } 206 207 // Note that this (sigchain-v1-style) reverse sig is made with the derived *per-team* signing key. 208 reverseSig, _, _, err := libkb.SignJSON(sigBodyBeforeReverse, perTeamSigningKey) 209 if err != nil { 210 return err 211 } 212 213 // Update the team section to include the reverse sig, sign it again, and 214 // make a sigchain-v2-style sig out of it. Doing it this way, instead of 215 // generating it twice with different parameters, makes it less likely to 216 // accidentally capture different global state (like ctime and merkle 217 // seqno). 218 sigBodyAfterReverse := sigBodyBeforeReverse 219 err = sigBodyAfterReverse.SetValueAtPath("body.team.per_team_key.reverse_sig", jsonw.NewString(reverseSig)) 220 if err != nil { 221 return err 222 } 223 224 sigJSONAfterReverse, err := sigBodyAfterReverse.Marshal() 225 if err != nil { 226 return err 227 } 228 seqType := seqTypeForTeamPublicness(public) 229 v2Sig, _, _, err := libkb.MakeSigchainV2OuterSig( 230 mctx, 231 deviceSigningKey, 232 libkb.LinkTypeTeamRoot, 233 1, /* seqno */ 234 sigJSONAfterReverse, 235 nil, /* prevLinkID */ 236 libkb.SigHasRevokes(false), 237 seqType, 238 libkb.SigIgnoreIfUnsupported(false), 239 nil, 240 ) 241 if err != nil { 242 return err 243 } 244 245 sigMultiItem := libkb.SigMultiItem{ 246 Sig: v2Sig, 247 SigningKID: deviceSigningKey.GetKID(), 248 Type: string(libkb.LinkTypeTeamRoot), 249 SeqType: seqType, 250 SigInner: string(sigJSONAfterReverse), 251 TeamID: teamID, 252 PublicKeys: &libkb.SigMultiItemPublicKeys{ 253 Encryption: perTeamEncryptionKey.GetKID(), 254 Signing: perTeamSigningKey.GetKID(), 255 }, 256 Version: libkb.KeybaseSignatureV2, 257 } 258 259 err = precheckLinkToPost(ctx, g, sigMultiItem, nil, me.ToUserVersion()) 260 if err != nil { 261 mctx.Debug("cannot post link (precheck): %v", err) 262 return err 263 } 264 265 mctx.Debug("makeSigAndPostRootTeam post sigs") 266 payload := make(libkb.JSONPayload) 267 payload["sigs"] = []interface{}{sigMultiItem} 268 payload["per_team_key"] = secretboxes 269 270 _, err = mctx.G().API.PostJSON(mctx, libkb.APIArg{ 271 Endpoint: "sig/multi", 272 SessionType: libkb.APISessionTypeREQUIRED, 273 JSONPayload: payload, 274 }) 275 if err != nil { 276 return err 277 } 278 mctx.Debug("makeSigAndPostRootTeam created team: %v", teamID) 279 return nil 280 } 281 282 func CreateRootTeam(ctx context.Context, g *libkb.GlobalContext, nameString string, settings keybase1.TeamSettings) (res *keybase1.TeamID, err error) { 283 defer g.CTrace(ctx, "CreateRootTeam", &err)() 284 285 perUserKeyUpgradeSoft(ctx, g, "create-root-team") 286 287 name, err := keybase1.TeamNameFromString(nameString) 288 if err != nil { 289 return nil, err 290 } 291 if !name.IsRootTeam() { 292 return nil, fmt.Errorf("cannot create root team with subteam name: %v", nameString) 293 } 294 295 merkleRoot, err := g.MerkleClient.FetchRootFromServer(libkb.NewMetaContext(ctx, g), libkb.TeamMerkleFreshnessForAdmin) 296 if err != nil { 297 return nil, err 298 } 299 300 g.Log.CDebugf(ctx, "CreateRootTeam load me") 301 me, err := loadMeForSignatures(ctx, g) 302 if err != nil { 303 return nil, err 304 } 305 306 ownerLatest := me.GetLatestPerUserKey() 307 if ownerLatest == nil { 308 return nil, errors.New("can't create a new team without having provisioned a per-user key") 309 } 310 secretboxRecipients := map[keybase1.UserVersion]keybase1.PerUserKey{ 311 me.ToUserVersion(): *ownerLatest, 312 } 313 314 members := SCTeamMembers{ 315 Owners: &[]SCTeamMember{SCTeamMember(me.ToUserVersion())}, 316 Admins: &[]SCTeamMember{}, 317 Writers: &[]SCTeamMember{}, 318 Readers: &[]SCTeamMember{}, 319 Bots: &[]SCTeamMember{}, 320 RestrictedBots: &[]SCTeamMember{}, 321 } 322 323 var scSettings *SCTeamSettings 324 if settings.Open { 325 settingsTemp, err := CreateTeamSettings(settings.Open, settings.JoinAs) 326 if err != nil { 327 return nil, err 328 } 329 scSettings = &settingsTemp 330 } 331 332 teamID := name.ToPrivateTeamID() 333 334 err = makeSigAndPostRootTeam(ctx, g, me, members, nil, 335 secretboxRecipients, name.String(), teamID, false, false, scSettings, *merkleRoot) 336 return &teamID, err 337 } 338 339 func CreateSubteam(ctx context.Context, g *libkb.GlobalContext, subteamBasename string, 340 parentName keybase1.TeamName, addSelfAs keybase1.TeamRole) (ret *keybase1.TeamID, err error) { 341 defer g.CTrace(ctx, "CreateSubteam", &err)() 342 mctx := libkb.NewMetaContext(ctx, g) 343 344 subteamName, err := parentName.Append(subteamBasename) 345 if err != nil { 346 return nil, err 347 } 348 349 // Assume private 350 public := false 351 subteamID := NewSubteamID(public) 352 353 err = ForceMerkleRootUpdateByTeamID(mctx, parentName.ToPrivateTeamID()) 354 if err != nil { 355 return nil, err 356 } 357 merkleRoot, err := g.MerkleClient.FetchRootFromServer(libkb.NewMetaContext(ctx, g), libkb.TeamMerkleFreshnessForAdmin) 358 if err != nil { 359 return nil, err 360 } 361 362 perUserKeyUpgradeSoft(ctx, mctx.G(), "create-subteam") 363 364 me, err := loadMeForSignatures(ctx, mctx.G()) 365 if err != nil { 366 return nil, err 367 } 368 369 deviceSigningKey, err := mctx.G().ActiveDevice.SigningKey() 370 if err != nil { 371 return nil, err 372 } 373 374 parentTeam, err := GetForTeamManagementByStringName(ctx, g, parentName.String(), true) 375 if err != nil { 376 return nil, err 377 } 378 379 admin, err := parentTeam.getAdminPermission(ctx) 380 if err != nil { 381 return nil, err 382 } 383 384 if err := parentTeam.ForceMerkleRootUpdate(ctx); err != nil { 385 return nil, err 386 } 387 388 // Subteam creation involves two links, one in the parent team's chain, and 389 // one to start the new subteam chain. The start of the new subteam chain 390 // (type "team.subteam_head") is very similar to the "team.root" sig that 391 // starts a root team, and so making that link is very similar to what the 392 // CreateTeamEngine does. 393 394 newSubteamSig, ratchet, err := generateNewSubteamSigForParentChain(mctx, me, deviceSigningKey, parentTeam.chain(), subteamName, subteamID, admin) 395 if err != nil { 396 return nil, err 397 } 398 399 // subteam needs to be keyed for all admins above it 400 allParentAdmins, err := parentTeam.AllAdmins(ctx) 401 if err != nil { 402 return nil, err 403 } 404 405 subteamHeadSig, secretboxes, err := generateHeadSigForSubteamChain(ctx, g, me, 406 deviceSigningKey, parentTeam.chain(), subteamName, subteamID, admin, 407 allParentAdmins, addSelfAs, *merkleRoot) 408 if err != nil { 409 return nil, err 410 } 411 412 err = precheckLinkToPost(ctx, g, *newSubteamSig, parentTeam.chain(), me.ToUserVersion()) 413 if err != nil { 414 return nil, fmt.Errorf("cannot post link (precheck new subteam): %v", err) 415 } 416 417 err = precheckLinkToPost(ctx, g, *subteamHeadSig, nil, me.ToUserVersion()) 418 if err != nil { 419 return nil, fmt.Errorf("cannot post link (precheck subteam head): %v", err) 420 } 421 422 payload := make(libkb.JSONPayload) 423 payload["sigs"] = []interface{}{newSubteamSig, subteamHeadSig} 424 payload["per_team_key"] = secretboxes 425 ratchet.AddToJSONPayload(payload) 426 427 _, err = g.API.PostJSON(mctx, libkb.APIArg{ 428 Endpoint: "sig/multi", 429 SessionType: libkb.APISessionTypeREQUIRED, 430 JSONPayload: payload, 431 }) 432 if err != nil { 433 return nil, err 434 } 435 436 return &subteamID, nil 437 } 438 439 func makeRootTeamSection(teamName string, teamID keybase1.TeamID, members SCTeamMembers, invites *SCTeamInvites, 440 perTeamSigningKID keybase1.KID, perTeamEncryptionKID keybase1.KID, public bool, implicit bool, settings *SCTeamSettings) (SCTeamSection, error) { 441 teamSection := SCTeamSection{ 442 Name: (*SCTeamName)(&teamName), 443 ID: (SCTeamID)(teamID), 444 Public: public, 445 Implicit: implicit, 446 PerTeamKey: &SCPerTeamKey{ 447 Generation: 1, 448 SigKID: perTeamSigningKID, 449 EncKID: perTeamEncryptionKID, 450 }, 451 Members: &members, 452 Invites: invites, 453 } 454 455 teamSection.Settings = settings 456 457 // At this point the team section has every field filled out except the 458 // reverse sig. Now we'll wrap it into a full sig, marshal it to JSON, and 459 // sign it, *twice*. The first time with the per-team signing key, to 460 // produce the reverse sig, and the second time with the device signing 461 // key, after the reverse sig has been written in. 462 463 return teamSection, nil 464 } 465 466 func generateNewSubteamSigForParentChain(m libkb.MetaContext, me libkb.UserForSignatures, signingKey libkb.GenericKey, parentTeam *TeamSigChainState, subteamName keybase1.TeamName, subteamID keybase1.TeamID, admin *SCTeamAdmin) (item *libkb.SigMultiItem, r *hidden.Ratchet, err error) { 467 newSubteamSigBody, ratchet, err := NewSubteamSig(m, me, signingKey, parentTeam, subteamName, subteamID, admin) 468 if err != nil { 469 return nil, nil, err 470 } 471 newSubteamSigJSON, err := newSubteamSigBody.Marshal() 472 if err != nil { 473 return nil, nil, err 474 } 475 476 prevLinkID, err := libkb.ImportLinkID(parentTeam.GetLatestLinkID()) 477 if err != nil { 478 return nil, nil, err 479 } 480 seqType := seqTypeForTeamPublicness(parentTeam.IsPublic()) 481 482 v2Sig, _, _, err := libkb.MakeSigchainV2OuterSig( 483 m, 484 signingKey, 485 libkb.LinkTypeNewSubteam, 486 parentTeam.GetLatestSeqno()+1, 487 newSubteamSigJSON, 488 prevLinkID, 489 libkb.SigHasRevokes(false), 490 seqType, 491 libkb.SigIgnoreIfUnsupported(false), 492 nil, 493 ) 494 if err != nil { 495 return nil, nil, err 496 } 497 498 item = &libkb.SigMultiItem{ 499 Sig: v2Sig, 500 SigningKID: signingKey.GetKID(), 501 Type: string(libkb.LinkTypeNewSubteam), 502 SeqType: seqType, 503 SigInner: string(newSubteamSigJSON), 504 TeamID: parentTeam.GetID(), 505 Version: libkb.KeybaseSignatureV2, 506 } 507 return item, ratchet, nil 508 } 509 510 func generateHeadSigForSubteamChain(ctx context.Context, g *libkb.GlobalContext, me libkb.UserForSignatures, 511 signingKey libkb.GenericKey, parentTeam *TeamSigChainState, subteamName keybase1.TeamName, 512 subteamID keybase1.TeamID, admin *SCTeamAdmin, allParentAdmins []keybase1.UserVersion, 513 addSelfAs keybase1.TeamRole, merkleRoot libkb.MerkleRoot) (item *libkb.SigMultiItem, boxes *PerTeamSharedSecretBoxes, err error) { 514 deviceEncryptionKey, err := g.ActiveDevice.EncryptionKey() 515 if err != nil { 516 return 517 } 518 519 members := SCTeamMembers{ 520 Owners: &[]SCTeamMember{}, 521 Admins: &[]SCTeamMember{}, 522 Writers: &[]SCTeamMember{}, 523 Readers: &[]SCTeamMember{}, 524 Bots: &[]SCTeamMember{}, 525 RestrictedBots: &[]SCTeamMember{}, 526 } 527 528 memSet := newMemberSet() 529 _, err = memSet.loadGroup(ctx, g, allParentAdmins, storeMemberKindRecipient, true /* force poll */) 530 if err != nil { 531 return nil, nil, err 532 } 533 534 if addSelfAs != keybase1.TeamRole_NONE { 535 meUV := me.ToUserVersion() 536 memList := []SCTeamMember{SCTeamMember(meUV)} 537 switch addSelfAs { 538 case keybase1.TeamRole_BOT: 539 members.Bots = &memList 540 case keybase1.TeamRole_READER: 541 members.Readers = &memList 542 case keybase1.TeamRole_WRITER: 543 members.Writers = &memList 544 case keybase1.TeamRole_ADMIN: 545 members.Admins = &memList 546 case keybase1.TeamRole_OWNER: 547 return nil, nil, errors.New("Cannot add self as owner to a subteam") 548 case keybase1.TeamRole_RESTRICTEDBOT: 549 return nil, nil, errors.New("Cannot add self as restricted bot to a subteam") 550 } 551 _, err := memSet.addMember(ctx, g, meUV, storeMemberKindRecipient, false /* force poll */) 552 if err != nil { 553 return nil, nil, err 554 } 555 } 556 557 // These boxes will get posted along with the sig below. 558 m, err := NewTeamKeyManager(g, subteamID) 559 if err != nil { 560 return nil, nil, err 561 } 562 boxes, err = m.SharedSecretBoxes(libkb.NewMetaContext(ctx, g), deviceEncryptionKey, memSet.recipients) 563 if err != nil { 564 return nil, nil, err 565 } 566 567 perTeamSigningKey, err := m.SigningKey() 568 if err != nil { 569 return nil, nil, err 570 } 571 perTeamEncryptionKey, err := m.EncryptionKey() 572 if err != nil { 573 return nil, nil, err 574 } 575 576 // The "team" section of a subchain head link is similar to that of a 577 // "team.root" link, with the addition of the "parent" subsection. 578 teamSection, err := makeSubteamTeamSection(subteamName, subteamID, parentTeam, members, perTeamSigningKey.GetKID(), perTeamEncryptionKey.GetKID(), admin) 579 if err != nil { 580 return 581 } 582 583 err = addSummaryHash(&teamSection, boxes) 584 if err != nil { 585 return nil, nil, err 586 } 587 588 subteamHeadSigBodyBeforeReverse, err := SubteamHeadSig(g, me, signingKey, teamSection, merkleRoot) 589 if err != nil { 590 return 591 } 592 593 // Now generate the reverse sig and edit it into the JSON. Note that this 594 // (sigchain-v1-style) reverse sig is made with the derived *per-team* 595 // signing key. 596 reverseSig, _, _, err := libkb.SignJSON(subteamHeadSigBodyBeforeReverse, perTeamSigningKey) 597 if err != nil { 598 return 599 } 600 601 // Update the team section to include the reverse sig, sign it again, and 602 // make a sigchain-v2-style sig out of it. Doing it this way, instead of 603 // generating it twice with different parameters, makes it less likely to 604 // accidentally capture different global state (like ctime and merkle 605 // seqno). 606 subteamHeadSigBodyAfterReverse := subteamHeadSigBodyBeforeReverse 607 err = subteamHeadSigBodyAfterReverse.SetValueAtPath("body.team.per_team_key.reverse_sig", jsonw.NewString(reverseSig)) 608 if err != nil { 609 return nil, nil, err 610 } 611 612 subteamHeadSigJSON, err := subteamHeadSigBodyAfterReverse.Marshal() 613 if err != nil { 614 return 615 } 616 617 seqType := seqTypeForTeamPublicness(parentTeam.IsPublic()) 618 v2Sig, _, _, err := libkb.MakeSigchainV2OuterSig( 619 libkb.NewMetaContext(ctx, g), 620 signingKey, 621 libkb.LinkTypeSubteamHead, 622 1, /* seqno */ 623 subteamHeadSigJSON, 624 nil, /* prevLinkID */ 625 libkb.SigHasRevokes(false), 626 seqType, 627 libkb.SigIgnoreIfUnsupported(false), 628 nil, 629 ) 630 if err != nil { 631 return 632 } 633 634 item = &libkb.SigMultiItem{ 635 Sig: v2Sig, 636 SigningKID: signingKey.GetKID(), 637 Type: string(libkb.LinkTypeSubteamHead), 638 SeqType: seqType, 639 SigInner: string(subteamHeadSigJSON), 640 TeamID: subteamID, 641 PublicKeys: &libkb.SigMultiItemPublicKeys{ 642 Encryption: perTeamEncryptionKey.GetKID(), 643 Signing: perTeamSigningKey.GetKID(), 644 }, 645 } 646 return 647 } 648 649 func makeSubteamTeamSection(subteamName keybase1.TeamName, subteamID keybase1.TeamID, 650 parentTeam *TeamSigChainState, members SCTeamMembers, perTeamSigningKID keybase1.KID, 651 perTeamEncryptionKID keybase1.KID, admin *SCTeamAdmin) (SCTeamSection, error) { 652 653 subteamName2 := subteamName.String() 654 teamSection := SCTeamSection{ 655 Name: (*SCTeamName)(&subteamName2), 656 ID: (SCTeamID)(subteamID), 657 Parent: &SCTeamParent{ 658 ID: SCTeamID(parentTeam.GetID()), 659 Seqno: parentTeam.GetLatestSeqno() + 1, // the seqno of the *new* parent link 660 SeqType: seqTypeForTeamPublicness(parentTeam.IsPublic()), 661 }, 662 PerTeamKey: &SCPerTeamKey{ 663 Generation: 1, 664 SigKID: perTeamSigningKID, 665 EncKID: perTeamEncryptionKID, 666 }, 667 Members: &members, 668 Admin: admin, 669 } 670 671 // At this point the team section has every field filled out except the 672 // reverse sig. Next we'll wrap it into a full sig body, marshal it to 673 // JSON, and sign it, *twice*. The first time with the per-team signing 674 // key, to produce the reverse sig, and the second time with the device 675 // signing key, after the reverse sig has been written in. 676 677 return teamSection, nil 678 } 679 680 // Get a per-user key. 681 // Wait for attempt but only warn on error. 682 func perUserKeyUpgradeSoft(ctx context.Context, g *libkb.GlobalContext, reason string) { 683 m := libkb.NewMetaContext(ctx, g) 684 arg := &engine.PerUserKeyUpgradeArgs{} 685 eng := engine.NewPerUserKeyUpgrade(g, arg) 686 err := engine.RunEngine2(m, eng) 687 if err != nil { 688 m.Debug("PerUserKeyUpgrade failed (%s): %v", reason, err) 689 } 690 }