@@ -3,7 +3,6 @@ package github
33import  (
44	"context" 
55	"encoding/base64" 
6- 	"errors" 
76	"fmt" 
87	"io" 
98	"net/http" 
@@ -12,12 +11,14 @@ import (
1211	"sync" 
1312	"text/template" 
1413
14+ 	"github.com/ProtonMail/go-crypto/openpgp" 
1515	"github.com/alist-org/alist/v3/drivers/base" 
1616	"github.com/alist-org/alist/v3/internal/driver" 
1717	"github.com/alist-org/alist/v3/internal/errs" 
1818	"github.com/alist-org/alist/v3/internal/model" 
1919	"github.com/alist-org/alist/v3/pkg/utils" 
2020	"github.com/go-resty/resty/v2" 
21+ 	"github.com/pkg/errors" 
2122	log "github.com/sirupsen/logrus" 
2223)
2324
@@ -33,6 +34,7 @@ type Github struct {
3334	moveMsgTmpl    * template.Template 
3435	isOnBranch     bool 
3536	commitMutex    sync.Mutex 
37+ 	pgpEntity      * openpgp.Entity 
3638}
3739
3840func  (d  * Github ) Config () driver.Config  {
@@ -102,6 +104,26 @@ func (d *Github) Init(ctx context.Context) error {
102104		_ , err  =  d .getBranchHead ()
103105		d .isOnBranch  =  err  ==  nil 
104106	}
107+ 	if  d .GPGPrivateKey  !=  ""  {
108+ 		if  d .CommitterName  ==  ""  ||  d .AuthorName  ==  ""  {
109+ 			user , e  :=  d .getAuthenticatedUser ()
110+ 			if  e  !=  nil  {
111+ 				return  e 
112+ 			}
113+ 			if  d .CommitterName  ==  ""  {
114+ 				d .CommitterName  =  user .Name 
115+ 				d .CommitterEmail  =  user .Email 
116+ 			}
117+ 			if  d .AuthorName  ==  ""  {
118+ 				d .AuthorName  =  user .Name 
119+ 				d .AuthorEmail  =  user .Email 
120+ 			}
121+ 		}
122+ 		d .pgpEntity , err  =  loadPrivateKey (d .GPGPrivateKey , d .GPGKeyPassphrase )
123+ 		if  err  !=  nil  {
124+ 			return  err 
125+ 		}
126+ 	}
105127	return  nil 
106128}
107129
@@ -174,10 +196,39 @@ func (d *Github) MakeDir(ctx context.Context, parentDir model.Obj, dirName strin
174196	if  parent .Entries  ==  nil  {
175197		return  errs .NotFolder 
176198	}
177- 	// if parent folder contains .gitkeep only, mark it and delete .gitkeep later 
178- 	gitKeepSha  :=  "" 
199+ 	subDirSha , err  :=  d .newTree ("" , []interface {}{
200+ 		map [string ]string {
201+ 			"path" :    ".gitkeep" ,
202+ 			"mode" :    "100644" ,
203+ 			"type" :    "blob" ,
204+ 			"content" : "" ,
205+ 		},
206+ 	})
207+ 	if  err  !=  nil  {
208+ 		return  err 
209+ 	}
210+ 	newTree  :=  make ([]interface {}, 0 , 2 )
211+ 	newTree  =  append (newTree , TreeObjReq {
212+ 		Path : dirName ,
213+ 		Mode : "040000" ,
214+ 		Type : "tree" ,
215+ 		Sha :  subDirSha ,
216+ 	})
179217	if  len (parent .Entries ) ==  1  &&  parent .Entries [0 ].Name  ==  ".gitkeep"  {
180- 		gitKeepSha  =  parent .Entries [0 ].Sha 
218+ 		newTree  =  append (newTree , TreeObjReq {
219+ 			Path : ".gitkeep" ,
220+ 			Mode : "100644" ,
221+ 			Type : "blob" ,
222+ 			Sha :  nil ,
223+ 		})
224+ 	}
225+ 	newSha , err  :=  d .newTree (parent .Sha , newTree )
226+ 	if  err  !=  nil  {
227+ 		return  err 
228+ 	}
229+ 	rootSha , err  :=  d .renewParentTrees (parentDir .GetPath (), parent .Sha , newSha , "/" )
230+ 	if  err  !=  nil  {
231+ 		return  err 
181232	}
182233
183234	commitMessage , err  :=  getMessage (d .mkdirMsgTmpl , & MessageTemplateVars {
@@ -190,13 +241,7 @@ func (d *Github) MakeDir(ctx context.Context, parentDir model.Obj, dirName strin
190241	if  err  !=  nil  {
191242		return  err 
192243	}
193- 	if  err  =  d .createGitKeep (stdpath .Join (parentDir .GetPath (), dirName ), commitMessage ); err  !=  nil  {
194- 		return  err 
195- 	}
196- 	if  gitKeepSha  !=  ""  {
197- 		err  =  d .delete (stdpath .Join (parentDir .GetPath (), ".gitkeep" ), gitKeepSha , commitMessage )
198- 	}
199- 	return  err 
244+ 	return  d .commit (commitMessage , rootSha )
200245}
201246
202247func  (d  * Github ) Move (ctx  context.Context , srcObj , dstDir  model.Obj ) error  {
@@ -639,24 +684,6 @@ func (d *Github) get(path string) (*Object, error) {
639684	return  & resp , err 
640685}
641686
642- func  (d  * Github ) createGitKeep (path , message  string ) error  {
643- 	body  :=  map [string ]interface {}{
644- 		"message" : message ,
645- 		"content" : "" ,
646- 		"branch" :  d .Ref ,
647- 	}
648- 	d .addCommitterAndAuthor (& body )
649- 
650- 	res , err  :=  d .client .R ().SetBody (body ).Put (d .getContentApiUrl (stdpath .Join (path , ".gitkeep" )))
651- 	if  err  !=  nil  {
652- 		return  err 
653- 	}
654- 	if  res .StatusCode () !=  200  &&  res .StatusCode () !=  201  {
655- 		return  toErr (res )
656- 	}
657- 	return  nil 
658- }
659- 
660687func  (d  * Github ) putBlob (ctx  context.Context , s  model.FileStreamer , up  driver.UpdateProgress ) (string , error ) {
661688	beforeContent  :=  "{\" encoding\" :\" base64\" ,\" content\" :\" " 
662689	afterContent  :=  "\" }" 
@@ -717,23 +744,6 @@ func (d *Github) putBlob(ctx context.Context, s model.FileStreamer, up driver.Up
717744	return  resp .Sha , nil 
718745}
719746
720- func  (d  * Github ) delete (path , sha , message  string ) error  {
721- 	body  :=  map [string ]interface {}{
722- 		"message" : message ,
723- 		"sha" :     sha ,
724- 		"branch" :  d .Ref ,
725- 	}
726- 	d .addCommitterAndAuthor (& body )
727- 	res , err  :=  d .client .R ().SetBody (body ).Delete (d .getContentApiUrl (path ))
728- 	if  err  !=  nil  {
729- 		return  err 
730- 	}
731- 	if  res .StatusCode () !=  200  {
732- 		return  toErr (res )
733- 	}
734- 	return  nil 
735- }
736- 
737747func  (d  * Github ) renewParentTrees (path , prevSha , curSha , until  string ) (string , error ) {
738748	for  path  !=  until  {
739749		path  =  stdpath .Dir (path )
@@ -795,11 +805,11 @@ func (d *Github) getTreeDirectly(path string) (*TreeResp, string, error) {
795805}
796806
797807func  (d  * Github ) newTree (baseSha  string , tree  []interface {}) (string , error ) {
798- 	res ,  err   :=  d . client . R (). 
799- 		 SetBody ( & TreeReq {
800- 			 BaseTree :  baseSha , 
801- 			 Trees :     tree , 
802- 		} ).
808+ 	body   :=  & TreeReq { Trees :  tree } 
809+ 	if   baseSha   !=   ""   {
810+ 		body . BaseTree   =   baseSha 
811+ 	} 
812+ 	res ,  err   :=   d . client . R (). SetBody ( body ).
803813		Post (fmt .Sprintf ("https://api.github.com/repos/%s/%s/git/trees" , d .Owner , d .Repo ))
804814	if  err  !=  nil  {
805815		return  "" , err 
@@ -822,6 +832,13 @@ func (d *Github) commit(message, treeSha string) error {
822832		"parents" : []string {oldCommit },
823833	}
824834	d .addCommitterAndAuthor (& body )
835+ 	if  d .pgpEntity  !=  nil  {
836+ 		signature , e  :=  signCommit (& body , d .pgpEntity )
837+ 		if  e  !=  nil  {
838+ 			return  e 
839+ 		}
840+ 		body ["signature" ] =  signature 
841+ 	}
825842	res , err  :=  d .client .R ().SetBody (body ).Post (fmt .Sprintf ("https://api.github.com/repos/%s/%s/git/commits" , d .Owner , d .Repo ))
826843	if  err  !=  nil  {
827844		return  err 
@@ -925,6 +942,21 @@ func (d *Github) getRepo() (*RepoResp, error) {
925942	return  & resp , nil 
926943}
927944
945+ func  (d  * Github ) getAuthenticatedUser () (* UserResp , error ) {
946+ 	res , err  :=  d .client .R ().Get ("https://api.github.com/user" )
947+ 	if  err  !=  nil  {
948+ 		return  nil , err 
949+ 	}
950+ 	if  res .StatusCode () !=  200  {
951+ 		return  nil , toErr (res )
952+ 	}
953+ 	resp  :=  & UserResp {}
954+ 	if  err  =  utils .Json .Unmarshal (res .Body (), resp ); err  !=  nil  {
955+ 		return  nil , err 
956+ 	}
957+ 	return  resp , nil 
958+ }
959+ 
928960func  (d  * Github ) addCommitterAndAuthor (m  * map [string ]interface {}) {
929961	if  d .CommitterName  !=  ""  {
930962		committer  :=  map [string ]string {
0 commit comments