package gitea import ( "code.gitea.io/sdk/gitea" "code.mrmelon54.xyz/sean/melon-tools/utils" "context" _ "embed" "encoding/gob" "fmt" "github.com/google/uuid" "github.com/gorilla/mux" "golang.org/x/oauth2" "html/template" "net/http" "os" ) //go:embed pages/index.go.html var indexTemplate string type Module struct { oauthClient *oauth2.Config sessionWrapper func(cb func(http.ResponseWriter, *http.Request, *utils.State)) func(rw http.ResponseWriter, req *http.Request) } type giteaKeyType int const ( GITEA_KEY_OAUTH_CLIENT = giteaKeyType(iota) GITEA_KEY_USER GITEA_KEY_STATE GITEA_KEY_ACCESS_TOKEN GITEA_KEY_REFRESH_TOKEN ) func New() *Module { gob.Register(new(giteaKeyType)) return &Module{} } func (m *Module) SetupModule(router *mux.Router, cb func(cb func(http.ResponseWriter, *http.Request, *utils.State)) func(rw http.ResponseWriter, req *http.Request)) { m.sessionWrapper = cb m.oauthClient = &oauth2.Config{ ClientID: os.Getenv("GITEA_CLIENT_ID"), ClientSecret: os.Getenv("GITEA_CLIENT_SECRET"), Scopes: []string{"openid"}, Endpoint: oauth2.Endpoint{ AuthURL: os.Getenv("GITEA_AUTHORIZE_URL"), TokenURL: os.Getenv("GITEA_TOKEN_URL"), }, RedirectURL: os.Getenv("GITEA_REDIRECT_URL"), } router.HandleFunc("/", m.getClient(m.homepage)) router.HandleFunc("/login", m.sessionWrapper(m.loginPage)) } func (m *Module) getClient(cb func(http.ResponseWriter, *http.Request, *utils.State, *gitea.Client)) func(rw http.ResponseWriter, req *http.Request) { return m.sessionWrapper(func(rw http.ResponseWriter, req *http.Request, state *utils.State) { if v, ok := utils.GetStateValue[*gitea.Client](state, GITEA_KEY_OAUTH_CLIENT); ok { cb(rw, req, state, v) return } http.Redirect(rw, req, "/gitea/login", http.StatusTemporaryRedirect) }) } func (m *Module) homepage(rw http.ResponseWriter, req *http.Request, state *utils.State, giteaClient *gitea.Client) { myUser, _, err := giteaClient.GetMyUserInfo() if err != nil { state.Del(GITEA_KEY_OAUTH_CLIENT) http.Error(rw, err.Error(), http.StatusInternalServerError) return } fmt.Println("Username:", myUser.UserName) orgs, _, err := giteaClient.ListMyOrgs(gitea.ListOrgsOptions{}) if err != nil { http.Error(rw, err.Error(), http.StatusInternalServerError) return } fmt.Println("Orgs:", orgs) orgSimple := make([]struct{ Name string }, len(orgs)) for i, j := range orgs { orgSimple[i] = struct{ Name string }{j.UserName} } tmp, err := template.New("homepage").Parse(indexTemplate) if err != nil { fmt.Println("Template parse error:", err) return } err = tmp.Execute(rw, struct { Username string Orgs []struct { Name string } }{ Username: myUser.UserName, Orgs: orgSimple, }) if err != nil { fmt.Println("Template execute error:", err) return } } func (m *Module) loginPage(rw http.ResponseWriter, req *http.Request, state *utils.State) { if myUser, ok := utils.GetStateValue[*string](state, GITEA_KEY_USER); ok { if myUser != nil { http.Redirect(rw, req, "/gitea", http.StatusTemporaryRedirect) return } } if flowState, ok := utils.GetStateValue[uuid.UUID](state, GITEA_KEY_STATE); ok { q := req.URL.Query() if q.Has("code") && q.Has("state") { if q.Get("state") == flowState.String() { exchange, err := m.oauthClient.Exchange(context.Background(), q.Get("code")) if err != nil { fmt.Println("Exchange token error:", err) return } c, err := gitea.NewClient(os.Getenv("GITEA_SERVER"), gitea.SetToken(exchange.AccessToken)) if err != nil { fmt.Println("Create client error:", err) return } state.Put(GITEA_KEY_OAUTH_CLIENT, c) http.Redirect(rw, req, "/gitea", http.StatusTemporaryRedirect) return } http.Error(rw, "OAuth flow state doesn't match\n", http.StatusBadRequest) return } } flowState := uuid.New() state.Put(GITEA_KEY_STATE, flowState) http.Redirect(rw, req, m.oauthClient.AuthCodeURL(flowState.String(), oauth2.AccessTypeOffline), http.StatusTemporaryRedirect) } func (m *Module) fetchRepos(giteaClient *gitea.Client) { repos, _, err := giteaClient.ListOrgRepos("snow", gitea.ListOrgReposOptions{ListOptions: gitea.ListOptions{Page: 0, PageSize: 100}}) if err != nil { fmt.Println(err) return } for _, myRepo := range repos { refs, _, err := giteaClient.GetRepoRefs("snow", myRepo.Name, "heads") if err != nil { fmt.Println(err) return } fmt.Println(len(refs)) for _, myRef := range refs { if myRef.Ref == "refs/heads/"+myRepo.DefaultBranch { fmt.Println(myRef.Ref) return } } fmt.Println("Can't find default branch") } }