github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/git/put.go (about) 1 package git 2 3 import ( 4 "context" 5 "encoding/base64" 6 "fmt" 7 8 "github.com/keybase/client/go/chat/globals" 9 "github.com/keybase/client/go/libkb" 10 "github.com/keybase/client/go/protocol/chat1" 11 "github.com/keybase/client/go/protocol/keybase1" 12 "github.com/keybase/go-codec/codec" 13 ) 14 15 func PutMetadata(ctx context.Context, g *libkb.GlobalContext, arg keybase1.PutGitMetadataArg) error { 16 teamer := NewTeamer(g) 17 cryptoer := NewCrypto(g) 18 mctx := libkb.NewMetaContext(ctx, g) 19 20 teamIDVis, err := teamer.LookupOrCreate(ctx, arg.Folder) 21 if err != nil { 22 return err 23 } 24 25 // Translate the GitLocalMetadata struct into GitLocalMetadataVersioned, 26 // for versioned storage. 27 localMetadataVersioned := keybase1.NewGitLocalMetadataVersionedWithV1( 28 keybase1.GitLocalMetadataV1{ 29 RepoName: arg.Metadata.RepoName}) 30 31 mh := codec.MsgpackHandle{WriteExt: true} 32 var msgpackLocalMetadata []byte 33 enc := codec.NewEncoderBytes(&msgpackLocalMetadata, &mh) 34 err = enc.Encode(localMetadataVersioned) 35 if err != nil { 36 return fmt.Errorf("encoding git metadata:%v", err) 37 } 38 encryptedMetadata, err := cryptoer.Box(ctx, msgpackLocalMetadata, teamIDVis) 39 if err != nil { 40 return err 41 } 42 base64Ciphertext := base64.StdEncoding.EncodeToString(encryptedMetadata.E) 43 base64Nonce := base64.StdEncoding.EncodeToString(encryptedMetadata.N[:]) 44 45 apiArg := libkb.APIArg{ 46 Endpoint: "kbfs/git/team/put", 47 SessionType: libkb.APISessionTypeREQUIRED, 48 Args: libkb.HTTPArgs{ 49 "team_id": libkb.S{Val: string(teamIDVis.TeamID)}, 50 "repo_id": libkb.S{Val: string(arg.RepoID)}, 51 "encrypted_metadata": libkb.S{Val: base64Ciphertext}, 52 "nonce": libkb.S{Val: base64Nonce}, 53 "key_generation": libkb.I{Val: int(encryptedMetadata.Gen)}, 54 "device_id": libkb.S{Val: string(g.Env.GetDeviceID())}, 55 "encryption_version": libkb.I{Val: encryptedMetadata.V}, 56 "notify_team": libkb.B{Val: arg.NotifyTeam}, 57 }, 58 } 59 _, err = mctx.G().GetAPI().Post(mctx, apiArg) 60 61 if err == nil { 62 err = sendChat(mctx, teamIDVis.TeamID, arg) 63 } 64 65 return err 66 } 67 68 func sendChat(mctx libkb.MetaContext, teamID keybase1.TeamID, arg keybase1.PutGitMetadataArg) error { 69 if arg.Folder.FolderType != keybase1.FolderType_TEAM { 70 // only send chat for team repos 71 return nil 72 } 73 74 settingsArg := keybase1.GetTeamRepoSettingsArg{ 75 Folder: arg.Folder, 76 RepoID: arg.RepoID, 77 } 78 settings, err := GetTeamRepoSettings(mctx.Ctx(), mctx.G(), settingsArg) 79 if err != nil { 80 return err 81 } 82 if settings.ChatDisabled { 83 return nil 84 } 85 if settings.ChannelName == nil { 86 // this shouldn't happen, but protect it if it does: 87 mctx.Debug("invalid team repo settings: chat enabled, but nil ChannelName. using default.") 88 settings.ChannelName = &globals.DefaultTeamTopic 89 } 90 91 if mctx.G().ChatHelper == nil { 92 mctx.Debug("cannot send chat on git push to team channel because no ChatHelper") 93 return nil 94 } 95 96 if arg.Metadata.PushType == keybase1.GitPushType_DEFAULT && keybase1.TotalNumberOfCommits(arg.Metadata.Refs) == 0 { 97 mctx.Debug("default git push and no commits, not sending chat") 98 return nil 99 } 100 101 mctx.G().StartStandaloneChat() 102 103 subBody := chat1.NewMessageSystemWithGitpush(chat1.MessageSystemGitPush{ 104 Team: arg.Folder.Name, 105 Pusher: mctx.G().Env.GetUsername().String(), 106 RepoID: arg.RepoID, 107 RepoName: string(arg.Metadata.RepoName), 108 Refs: arg.Metadata.Refs, 109 PushType: arg.Metadata.PushType, 110 PreviousRepoName: string(arg.Metadata.PreviousRepoName), 111 }) 112 body := chat1.NewMessageBodyWithSystem(subBody) 113 114 mctx.Debug("sending git push system chat message to %s/%s", arg.Folder.Name, *settings.ChannelName) 115 _, err = mctx.G().ChatHelper.SendMsgByNameNonblock(mctx.Ctx(), arg.Folder.Name, settings.ChannelName, 116 chat1.ConversationMembersType_TEAM, keybase1.TLFIdentifyBehavior_CHAT_CLI, body, 117 chat1.MessageType_SYSTEM, nil) 118 return err 119 }