diff --git a/.air/appview.toml b/.air/appview.toml
index 01efc93c..877f17ce 100644
--- a/.air/appview.toml
+++ b/.air/appview.toml
@@ -1,6 +1,6 @@
[build]
cmd = "tailwindcss -i input.css -o ./appview/pages/static/tw.css && go build -o .bin/app ./cmd/appview/main.go"
-bin = ".bin/app"
+bin = ";set -o allexport && source .env && set +o allexport; .bin/app"
root = "."
exclude_regex = [".*_templ.go"]
diff --git a/appview/config.go b/appview/config.go
index c7d321ca..7d82b281 100644
--- a/appview/config.go
+++ b/appview/config.go
@@ -6,17 +6,44 @@ import (
"github.com/sethvargo/go-envconfig"
)
+type CoreConfig struct {
+ CookieSecret string `env:"COOKIE_SECRET, default=00000000000000000000000000000000"`
+ DbPath string `env:"DB_PATH, default=appview.db"`
+ ListenAddr string `env:"LISTEN_ADDR, default=0.0.0.0:3000"`
+ AppviewHost string `env:"APPVIEW_HOST, default=https://tangled.sh"`
+ Dev bool `env:"DEV, default=false"`
+}
+
+type OAuthConfig struct {
+ Jwks string `env:"JWKS"`
+ ServerMetadataUrl string `env:"SERVER_METADATA_URL"`
+}
+
+type JetstreamConfig struct {
+ Endpoint string `env:"ENDPOINT, default=wss://jetstream1.us-east.bsky.network/subscribe"`
+}
+
+type ResendConfig struct {
+ ApiKey string `env:"API_KEY"`
+}
+
+type CamoConfig struct {
+ Host string `env:"HOST, default=https://camo.tangled.sh"`
+ SharedSecret string `env:"SHARED_SECRET"`
+}
+
+type AvatarConfig struct {
+ Host string `env:"HOST, default=https://avatar.tangled.sh"`
+ SharedSecret string `env:"SHARED_SECRET"`
+}
+
type Config struct {
- CookieSecret string `env:"TANGLED_COOKIE_SECRET, default=00000000000000000000000000000000"`
- DbPath string `env:"TANGLED_DB_PATH, default=appview.db"`
- ListenAddr string `env:"TANGLED_LISTEN_ADDR, default=0.0.0.0:3000"`
- Dev bool `env:"TANGLED_DEV, default=false"`
- JetstreamEndpoint string `env:"TANGLED_JETSTREAM_ENDPOINT, default=wss://jetstream1.us-east.bsky.network/subscribe"`
- ResendApiKey string `env:"TANGLED_RESEND_API_KEY"`
- CamoHost string `env:"TANGLED_CAMO_HOST, default=https://camo.tangled.sh"`
- CamoSharedSecret string `env:"TANGLED_CAMO_SHARED_SECRET"`
- AvatarSharedSecret string `env:"TANGLED_AVATAR_SHARED_SECRET"`
- AvatarHost string `env:"TANGLED_AVATAR_HOST, default=https://avatar.tangled.sh"`
+ Core CoreConfig `env:",prefix=TANGLED_"`
+ Jetstream JetstreamConfig `env:",prefix=TANGLED_JETSTREAM_"`
+ Resend ResendConfig `env:",prefix=TANGLED_RESEND_"`
+ Camo CamoConfig `env:",prefix=TANGLED_CAMO_"`
+ Avatar AvatarConfig `env:",prefix=TANGLED_AVATAR_"`
+ OAuth OAuthConfig `env:",prefix=TANGLED_OAUTH_"`
}
func LoadConfig(ctx context.Context) (*Config, error) {
diff --git a/appview/consts.go b/appview/consts.go
index 3a15eb1b..ea86179b 100644
--- a/appview/consts.go
+++ b/appview/consts.go
@@ -9,4 +9,7 @@ const (
SessionRefreshJwt = "refreshJwt"
SessionExpiry = "expiry"
SessionAuthenticated = "authenticated"
+
+ SessionDpopPrivateJwk = "dpopPrivateJwk"
+ SessionDpopAuthServerNonce = "dpopAuthServerNonce"
)
diff --git a/appview/db/db.go b/appview/db/db.go
index eb190533..b5339da0 100644
--- a/appview/db/db.go
+++ b/appview/db/db.go
@@ -288,6 +288,32 @@ func Make(dbPath string) (*DB, error) {
foreign key (at_uri) references repos(at_uri) on delete cascade
);
+ create table if not exists oauth_requests (
+ id integer primary key autoincrement,
+ auth_server_iss text not null,
+ state text not null,
+ did text not null,
+ handle text not null,
+ pds_url text not null,
+ pkce_verifier text not null,
+ dpop_auth_server_nonce text not null,
+ dpop_private_jwk text not null
+ );
+
+ create table if not exists oauth_sessions (
+ id integer primary key autoincrement,
+ did text not null,
+ handle text not null,
+ pds_url text not null,
+ auth_server_iss text not null,
+ access_jwt text not null,
+ refresh_jwt text not null,
+ dpop_pds_nonce text,
+ dpop_auth_server_nonce text not null,
+ dpop_private_jwk text not null,
+ expiry text not null
+ );
+
create table if not exists migrations (
id integer primary key autoincrement,
name text unique
diff --git a/appview/db/oauth.go b/appview/db/oauth.go
new file mode 100644
index 00000000..684f9090
--- /dev/null
+++ b/appview/db/oauth.go
@@ -0,0 +1,173 @@
+package db
+
+type OAuthRequest struct {
+ ID uint
+ AuthserverIss string
+ Handle string
+ State string
+ Did string
+ PdsUrl string
+ PkceVerifier string
+ DpopAuthserverNonce string
+ DpopPrivateJwk string
+}
+
+func SaveOAuthRequest(e Execer, oauthRequest OAuthRequest) error {
+ _, err := e.Exec(`
+ insert into oauth_requests (
+ auth_server_iss,
+ state,
+ handle,
+ did,
+ pds_url,
+ pkce_verifier,
+ dpop_auth_server_nonce,
+ dpop_private_jwk
+ ) values (?, ?, ?, ?, ?, ?, ?, ?)`,
+ oauthRequest.AuthserverIss,
+ oauthRequest.State,
+ oauthRequest.Handle,
+ oauthRequest.Did,
+ oauthRequest.PdsUrl,
+ oauthRequest.PkceVerifier,
+ oauthRequest.DpopAuthserverNonce,
+ oauthRequest.DpopPrivateJwk,
+ )
+ return err
+}
+
+func GetOAuthRequestByState(e Execer, state string) (OAuthRequest, error) {
+ var req OAuthRequest
+ err := e.QueryRow(`
+ select
+ id,
+ auth_server_iss,
+ handle,
+ state,
+ did,
+ pds_url,
+ pkce_verifier,
+ dpop_auth_server_nonce,
+ dpop_private_jwk
+ from oauth_requests
+ where state = ?`, state).Scan(
+ &req.ID,
+ &req.AuthserverIss,
+ &req.Handle,
+ &req.State,
+ &req.Did,
+ &req.PdsUrl,
+ &req.PkceVerifier,
+ &req.DpopAuthserverNonce,
+ &req.DpopPrivateJwk,
+ )
+ return req, err
+}
+
+func DeleteOAuthRequestByState(e Execer, state string) error {
+ _, err := e.Exec(`
+ delete from oauth_requests
+ where state = ?`, state)
+ return err
+}
+
+type OAuthSession struct {
+ ID uint
+ Handle string
+ Did string
+ PdsUrl string
+ AccessJwt string
+ RefreshJwt string
+ AuthServerIss string
+ DpopPdsNonce string
+ DpopAuthserverNonce string
+ DpopPrivateJwk string
+ Expiry string
+}
+
+func SaveOAuthSession(e Execer, session OAuthSession) error {
+ _, err := e.Exec(`
+ insert into oauth_sessions (
+ did,
+ handle,
+ pds_url,
+ access_jwt,
+ refresh_jwt,
+ auth_server_iss,
+ dpop_auth_server_nonce,
+ dpop_private_jwk,
+ expiry
+ ) values (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
+ session.Did,
+ session.Handle,
+ session.PdsUrl,
+ session.AccessJwt,
+ session.RefreshJwt,
+ session.AuthServerIss,
+ session.DpopAuthserverNonce,
+ session.DpopPrivateJwk,
+ session.Expiry,
+ )
+ return err
+}
+
+func RefreshOAuthSession(e Execer, did string, accessJwt, refreshJwt, expiry string) error {
+ _, err := e.Exec(`
+ update oauth_sessions
+ set access_jwt = ?, refresh_jwt = ?, expiry = ?
+ where did = ?`,
+ accessJwt,
+ refreshJwt,
+ expiry,
+ did,
+ )
+ return err
+}
+
+func GetOAuthSessionByDid(e Execer, did string) (*OAuthSession, error) {
+ var session OAuthSession
+ err := e.QueryRow(`
+ select
+ id,
+ did,
+ handle,
+ pds_url,
+ access_jwt,
+ refresh_jwt,
+ auth_server_iss,
+ dpop_auth_server_nonce,
+ dpop_private_jwk,
+ expiry
+ from oauth_sessions
+ where did = ?`, did).Scan(
+ &session.ID,
+ &session.Did,
+ &session.Handle,
+ &session.PdsUrl,
+ &session.AccessJwt,
+ &session.RefreshJwt,
+ &session.AuthServerIss,
+ &session.DpopAuthserverNonce,
+ &session.DpopPrivateJwk,
+ &session.Expiry,
+ )
+ return &session, err
+}
+
+func DeleteOAuthSessionByDid(e Execer, did string) error {
+ _, err := e.Exec(`
+ delete from oauth_sessions
+ where did = ?`, did)
+ return err
+}
+
+func UpdateDpopPdsNonce(e Execer, did string, dpopPdsNonce string) error {
+ _, err := e.Exec(`
+ update oauth_sessions
+ set dpop_pds_nonce = ?
+ where did = ?`,
+ dpopPdsNonce,
+ did,
+ )
+ return err
+}
diff --git a/appview/middleware/middleware.go b/appview/middleware/middleware.go
index 51aa75fd..60d90b51 100644
--- a/appview/middleware/middleware.go
+++ b/appview/middleware/middleware.go
@@ -5,18 +5,14 @@ import (
"log"
"net/http"
"strconv"
- "time"
- comatproto "github.com/bluesky-social/indigo/api/atproto"
- "github.com/bluesky-social/indigo/xrpc"
- "tangled.sh/tangled.sh/core/appview"
- "tangled.sh/tangled.sh/core/appview/auth"
+ "tangled.sh/tangled.sh/core/appview/oauth"
"tangled.sh/tangled.sh/core/appview/pagination"
)
type Middleware func(http.Handler) http.Handler
-func AuthMiddleware(a *auth.Auth) Middleware {
+func AuthMiddleware(a *oauth.OAuth) Middleware {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
redirectFunc := func(w http.ResponseWriter, r *http.Request) {
@@ -29,68 +25,19 @@ func AuthMiddleware(a *auth.Auth) Middleware {
}
}
- session, err := a.GetSession(r)
- if session.IsNew || err != nil {
+ _, auth, err := a.GetSession(r)
+ if err != nil {
log.Printf("not logged in, redirecting")
redirectFunc(w, r)
return
}
- authorized, ok := session.Values[appview.SessionAuthenticated].(bool)
- if !ok || !authorized {
+ if !auth {
log.Printf("not logged in, redirecting")
redirectFunc(w, r)
return
}
- // refresh if nearing expiry
- // TODO: dedup with /login
- expiryStr := session.Values[appview.SessionExpiry].(string)
- expiry, err := time.Parse(time.RFC3339, expiryStr)
- if err != nil {
- log.Println("invalid expiry time", err)
- redirectFunc(w, r)
- return
- }
- pdsUrl, ok1 := session.Values[appview.SessionPds].(string)
- did, ok2 := session.Values[appview.SessionDid].(string)
- refreshJwt, ok3 := session.Values[appview.SessionRefreshJwt].(string)
-
- if !ok1 || !ok2 || !ok3 {
- log.Println("invalid expiry time", err)
- redirectFunc(w, r)
- return
- }
-
- if time.Now().After(expiry) {
- log.Println("token expired, refreshing ...")
-
- client := xrpc.Client{
- Host: pdsUrl,
- Auth: &xrpc.AuthInfo{
- Did: did,
- AccessJwt: refreshJwt,
- RefreshJwt: refreshJwt,
- },
- }
- atSession, err := comatproto.ServerRefreshSession(r.Context(), &client)
- if err != nil {
- log.Println("failed to refresh session", err)
- redirectFunc(w, r)
- return
- }
-
- sessionish := auth.RefreshSessionWrapper{atSession}
-
- err = a.StoreSession(r, w, &sessionish, pdsUrl)
- if err != nil {
- log.Printf("failed to store session for did: %s\n: %s", atSession.Did, err)
- return
- }
-
- log.Println("successfully refreshed token")
- }
-
next.ServeHTTP(w, r)
})
}
diff --git a/appview/oauth/oauth.go b/appview/oauth/oauth.go
index 07c9062f..1cdd190b 100644
--- a/appview/oauth/oauth.go
+++ b/appview/oauth/oauth.go
@@ -48,6 +48,8 @@ func (o *OAuth) SaveSession(w http.ResponseWriter, r *http.Request, oreq db.OAut
}
userSession.Values[appview.SessionDid] = oreq.Did
+ userSession.Values[appview.SessionHandle] = oreq.Handle
+ userSession.Values[appview.SessionPds] = oreq.PdsUrl
userSession.Values[appview.SessionAuthenticated] = true
err = userSession.Save(r, w)
if err != nil {
diff --git a/appview/pages/pages.go b/appview/pages/pages.go
index ae18d026..58af5e77 100644
--- a/appview/pages/pages.go
+++ b/appview/pages/pages.go
@@ -16,8 +16,8 @@ import (
"strings"
"tangled.sh/tangled.sh/core/appview"
- "tangled.sh/tangled.sh/core/appview/auth"
"tangled.sh/tangled.sh/core/appview/db"
+ "tangled.sh/tangled.sh/core/appview/oauth"
"tangled.sh/tangled.sh/core/appview/pages/markup"
"tangled.sh/tangled.sh/core/appview/pages/repoinfo"
"tangled.sh/tangled.sh/core/appview/pagination"
@@ -48,14 +48,14 @@ type Pages struct {
func NewPages(config *appview.Config) *Pages {
// initialized with safe defaults, can be overriden per use
rctx := &markup.RenderContext{
- IsDev: config.Dev,
- CamoUrl: config.CamoHost,
- CamoSecret: config.CamoSharedSecret,
+ IsDev: config.Core.Dev,
+ CamoUrl: config.Camo.Host,
+ CamoSecret: config.Camo.SharedSecret,
}
p := &Pages{
t: make(map[string]*template.Template),
- dev: config.Dev,
+ dev: config.Core.Dev,
embedFS: Files,
rctx: rctx,
templateDir: "appview/pages",
@@ -249,8 +249,12 @@ func (p *Pages) Login(w io.Writer, params LoginParams) error {
return p.executePlain("user/login", w, params)
}
+func (p *Pages) OAuthLogin(w io.Writer, params LoginParams) error {
+ return p.executePlain("user/oauthlogin", w, params)
+}
+
type TimelineParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
Timeline []db.TimelineEvent
DidHandleMap map[string]string
}
@@ -260,7 +264,7 @@ func (p *Pages) Timeline(w io.Writer, params TimelineParams) error {
}
type SettingsParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
PubKeys []db.PublicKey
Emails []db.Email
}
@@ -270,7 +274,7 @@ func (p *Pages) Settings(w io.Writer, params SettingsParams) error {
}
type KnotsParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
Registrations []db.Registration
}
@@ -279,7 +283,7 @@ func (p *Pages) Knots(w io.Writer, params KnotsParams) error {
}
type KnotParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
DidHandleMap map[string]string
Registration *db.Registration
Members []string
@@ -291,7 +295,7 @@ func (p *Pages) Knot(w io.Writer, params KnotParams) error {
}
type NewRepoParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
Knots []string
}
@@ -300,7 +304,7 @@ func (p *Pages) NewRepo(w io.Writer, params NewRepoParams) error {
}
type ForkRepoParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
Knots []string
RepoInfo repoinfo.RepoInfo
}
@@ -310,7 +314,7 @@ func (p *Pages) ForkRepo(w io.Writer, params ForkRepoParams) error {
}
type ProfilePageParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
Repos []db.Repo
CollaboratingRepos []db.Repo
ProfileTimeline *db.ProfileTimeline
@@ -335,7 +339,7 @@ func (p *Pages) ProfilePage(w io.Writer, params ProfilePageParams) error {
}
type ReposPageParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
Repos []db.Repo
Card ProfileCard
@@ -356,7 +360,7 @@ func (p *Pages) FollowFragment(w io.Writer, params FollowFragmentParams) error {
}
type EditBioParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
Profile *db.Profile
}
@@ -365,7 +369,7 @@ func (p *Pages) EditBioFragment(w io.Writer, params EditBioParams) error {
}
type EditPinsParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
Profile *db.Profile
AllRepos []PinnedRepo
DidHandleMap map[string]string
@@ -403,7 +407,7 @@ func (p *Pages) RepoDescriptionFragment(w io.Writer, params RepoDescriptionParam
}
type RepoIndexParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
RepoInfo repoinfo.RepoInfo
Active string
TagMap map[string][]string
@@ -444,7 +448,7 @@ func (p *Pages) RepoIndexPage(w io.Writer, params RepoIndexParams) error {
}
type RepoLogParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
RepoInfo repoinfo.RepoInfo
TagMap map[string][]string
types.RepoLogResponse
@@ -458,7 +462,7 @@ func (p *Pages) RepoLog(w io.Writer, params RepoLogParams) error {
}
type RepoCommitParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
RepoInfo repoinfo.RepoInfo
Active string
EmailToDidOrHandle map[string]string
@@ -472,7 +476,7 @@ func (p *Pages) RepoCommit(w io.Writer, params RepoCommitParams) error {
}
type RepoTreeParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
RepoInfo repoinfo.RepoInfo
Active string
BreadCrumbs [][]string
@@ -508,7 +512,7 @@ func (p *Pages) RepoTree(w io.Writer, params RepoTreeParams) error {
}
type RepoBranchesParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
RepoInfo repoinfo.RepoInfo
Active string
types.RepoBranchesResponse
@@ -520,7 +524,7 @@ func (p *Pages) RepoBranches(w io.Writer, params RepoBranchesParams) error {
}
type RepoTagsParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
RepoInfo repoinfo.RepoInfo
Active string
types.RepoTagsResponse
@@ -534,7 +538,7 @@ func (p *Pages) RepoTags(w io.Writer, params RepoTagsParams) error {
}
type RepoArtifactParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
RepoInfo repoinfo.RepoInfo
Artifact db.Artifact
}
@@ -544,7 +548,7 @@ func (p *Pages) RepoArtifactFragment(w io.Writer, params RepoArtifactParams) err
}
type RepoBlobParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
RepoInfo repoinfo.RepoInfo
Active string
BreadCrumbs [][]string
@@ -606,7 +610,7 @@ type Collaborator struct {
}
type RepoSettingsParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
RepoInfo repoinfo.RepoInfo
Collaborators []Collaborator
Active string
@@ -622,7 +626,7 @@ func (p *Pages) RepoSettings(w io.Writer, params RepoSettingsParams) error {
}
type RepoIssuesParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
RepoInfo repoinfo.RepoInfo
Active string
Issues []db.Issue
@@ -637,7 +641,7 @@ func (p *Pages) RepoIssues(w io.Writer, params RepoIssuesParams) error {
}
type RepoSingleIssueParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
RepoInfo repoinfo.RepoInfo
Active string
Issue db.Issue
@@ -659,7 +663,7 @@ func (p *Pages) RepoSingleIssue(w io.Writer, params RepoSingleIssueParams) error
}
type RepoNewIssueParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
RepoInfo repoinfo.RepoInfo
Active string
}
@@ -670,7 +674,7 @@ func (p *Pages) RepoNewIssue(w io.Writer, params RepoNewIssueParams) error {
}
type EditIssueCommentParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
RepoInfo repoinfo.RepoInfo
Issue *db.Issue
Comment *db.Comment
@@ -681,7 +685,7 @@ func (p *Pages) EditIssueCommentFragment(w io.Writer, params EditIssueCommentPar
}
type SingleIssueCommentParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
DidHandleMap map[string]string
RepoInfo repoinfo.RepoInfo
Issue *db.Issue
@@ -693,7 +697,7 @@ func (p *Pages) SingleIssueCommentFragment(w io.Writer, params SingleIssueCommen
}
type RepoNewPullParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
RepoInfo repoinfo.RepoInfo
Branches []types.Branch
Active string
@@ -705,7 +709,7 @@ func (p *Pages) RepoNewPull(w io.Writer, params RepoNewPullParams) error {
}
type RepoPullsParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
RepoInfo repoinfo.RepoInfo
Pulls []*db.Pull
Active string
@@ -737,7 +741,7 @@ func (r ResubmitResult) Unknown() bool {
}
type RepoSinglePullParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
RepoInfo repoinfo.RepoInfo
Active string
DidHandleMap map[string]string
@@ -752,7 +756,7 @@ func (p *Pages) RepoSinglePull(w io.Writer, params RepoSinglePullParams) error {
}
type RepoPullPatchParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
DidHandleMap map[string]string
RepoInfo repoinfo.RepoInfo
Pull *db.Pull
@@ -767,7 +771,7 @@ func (p *Pages) RepoPullPatchPage(w io.Writer, params RepoPullPatchParams) error
}
type RepoPullInterdiffParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
DidHandleMap map[string]string
RepoInfo repoinfo.RepoInfo
Pull *db.Pull
@@ -817,7 +821,7 @@ func (p *Pages) PullCompareForkBranchesFragment(w io.Writer, params PullCompareF
}
type PullResubmitParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
RepoInfo repoinfo.RepoInfo
Pull *db.Pull
SubmissionId int
@@ -828,7 +832,7 @@ func (p *Pages) PullResubmitFragment(w io.Writer, params PullResubmitParams) err
}
type PullActionsParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
RepoInfo repoinfo.RepoInfo
Pull *db.Pull
RoundNumber int
@@ -841,7 +845,7 @@ func (p *Pages) PullActionsFragment(w io.Writer, params PullActionsParams) error
}
type PullNewCommentParams struct {
- LoggedInUser *auth.User
+ LoggedInUser *oauth.User
RepoInfo repoinfo.RepoInfo
Pull *db.Pull
RoundNumber int
diff --git a/appview/pages/templates/user/oauthlogin.html b/appview/pages/templates/user/oauthlogin.html
new file mode 100644
index 00000000..1eaaead1
--- /dev/null
+++ b/appview/pages/templates/user/oauthlogin.html
@@ -0,0 +1,71 @@
+{{ define "user/oauthlogin" }}
+
+
+
+
+
+
+
+ login
+
+
+
+
+ tangled
+
+
+ tightly-knit social coding.
+
+
+
+ Join our Discord or
+ IRC channel:
+ #tangled on Libera Chat.
+
+
+
+
+
+{{ end }}
diff --git a/appview/settings/settings.go b/appview/settings/settings.go
index 1fafa210..a2b57a28 100644
--- a/appview/settings/settings.go
+++ b/appview/settings/settings.go
@@ -13,10 +13,10 @@ import (
"github.com/go-chi/chi/v5"
"tangled.sh/tangled.sh/core/api/tangled"
"tangled.sh/tangled.sh/core/appview"
- "tangled.sh/tangled.sh/core/appview/auth"
"tangled.sh/tangled.sh/core/appview/db"
"tangled.sh/tangled.sh/core/appview/email"
"tangled.sh/tangled.sh/core/appview/middleware"
+ "tangled.sh/tangled.sh/core/appview/oauth"
"tangled.sh/tangled.sh/core/appview/pages"
comatproto "github.com/bluesky-social/indigo/api/atproto"
@@ -27,7 +27,7 @@ import (
type Settings struct {
Db *db.DB
- Auth *auth.Auth
+ OAuth *oauth.OAuth
Pages *pages.Pages
Config *appview.Config
}
@@ -35,7 +35,7 @@ type Settings struct {
func (s *Settings) Router() http.Handler {
r := chi.NewRouter()
- r.Use(middleware.AuthMiddleware(s.Auth))
+ r.Use(middleware.AuthMiddleware(s.OAuth))
r.Get("/", s.settings)
@@ -56,7 +56,7 @@ func (s *Settings) Router() http.Handler {
}
func (s *Settings) settings(w http.ResponseWriter, r *http.Request) {
- user := s.Auth.GetUser(r)
+ user := s.OAuth.GetUser(r)
pubKeys, err := db.GetPublicKeys(s.Db, user.Did)
if err != nil {
log.Println(err)
@@ -79,7 +79,7 @@ func (s *Settings) buildVerificationEmail(emailAddr, did, code string) email.Ema
verifyURL := s.verifyUrl(did, emailAddr, code)
return email.Email{
- APIKey: s.Config.ResendApiKey,
+ APIKey: s.Config.Resend.ApiKey,
From: "noreply@notifs.tangled.sh",
To: emailAddr,
Subject: "Verify your Tangled email",
@@ -111,7 +111,7 @@ func (s *Settings) emails(w http.ResponseWriter, r *http.Request) {
log.Println("unimplemented")
return
case http.MethodPut:
- did := s.Auth.GetDid(r)
+ did := s.OAuth.GetDid(r)
emAddr := r.FormValue("email")
emAddr = strings.TrimSpace(emAddr)
@@ -174,7 +174,7 @@ func (s *Settings) emails(w http.ResponseWriter, r *http.Request) {
s.Pages.Notice(w, "settings-emails-success", "Click the link in the email we sent you to verify your email address.")
return
case http.MethodDelete:
- did := s.Auth.GetDid(r)
+ did := s.OAuth.GetDid(r)
emailAddr := r.FormValue("email")
emailAddr = strings.TrimSpace(emailAddr)
@@ -207,8 +207,8 @@ func (s *Settings) emails(w http.ResponseWriter, r *http.Request) {
func (s *Settings) verifyUrl(did string, email string, code string) string {
var appUrl string
- if s.Config.Dev {
- appUrl = "http://" + s.Config.ListenAddr
+ if s.Config.Core.Dev {
+ appUrl = "http://" + s.Config.Core.ListenAddr
} else {
appUrl = "https://tangled.sh"
}
@@ -252,7 +252,7 @@ func (s *Settings) emailsVerifyResend(w http.ResponseWriter, r *http.Request) {
return
}
- did := s.Auth.GetDid(r)
+ did := s.OAuth.GetDid(r)
emAddr := r.FormValue("email")
emAddr = strings.TrimSpace(emAddr)
@@ -323,7 +323,7 @@ func (s *Settings) emailsVerifyResend(w http.ResponseWriter, r *http.Request) {
}
func (s *Settings) emailsPrimary(w http.ResponseWriter, r *http.Request) {
- did := s.Auth.GetDid(r)
+ did := s.OAuth.GetDid(r)
emailAddr := r.FormValue("email")
emailAddr = strings.TrimSpace(emailAddr)
@@ -348,13 +348,17 @@ func (s *Settings) keys(w http.ResponseWriter, r *http.Request) {
log.Println("unimplemented")
return
case http.MethodPut:
- did := s.Auth.GetDid(r)
+ did := s.OAuth.GetDid(r)
key := r.FormValue("key")
key = strings.TrimSpace(key)
name := r.FormValue("name")
- client, _ := s.Auth.AuthorizedClient(r)
+ client, err := s.OAuth.AuthorizedClient(r)
+ if err != nil {
+ s.Pages.Notice(w, "settings-keys", "Failed to authorize. Try again later.")
+ return
+ }
- _, _, _, _, err := ssh.ParseAuthorizedKey([]byte(key))
+ _, _, _, _, err = ssh.ParseAuthorizedKey([]byte(key))
if err != nil {
log.Printf("parsing public key: %s", err)
s.Pages.Notice(w, "settings-keys", "That doesn't look like a valid public key. Make sure it's a public key.")
@@ -378,7 +382,7 @@ func (s *Settings) keys(w http.ResponseWriter, r *http.Request) {
}
// store in pds too
- resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
+ resp, err := client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
Collection: tangled.PublicKeyNSID,
Repo: did,
Rkey: rkey,
@@ -409,7 +413,7 @@ func (s *Settings) keys(w http.ResponseWriter, r *http.Request) {
return
case http.MethodDelete:
- did := s.Auth.GetDid(r)
+ did := s.OAuth.GetDid(r)
q := r.URL.Query()
name := q.Get("name")
@@ -420,7 +424,12 @@ func (s *Settings) keys(w http.ResponseWriter, r *http.Request) {
log.Println(rkey)
log.Println(key)
- client, _ := s.Auth.AuthorizedClient(r)
+ client, err := s.OAuth.AuthorizedClient(r)
+ if err != nil {
+ log.Printf("failed to authorize client: %s", err)
+ s.Pages.Notice(w, "settings-keys", "Failed to authorize client.")
+ return
+ }
if err := db.DeletePublicKey(s.Db, did, name, key); err != nil {
log.Printf("removing public key: %s", err)
@@ -430,7 +439,7 @@ func (s *Settings) keys(w http.ResponseWriter, r *http.Request) {
if rkey != "" {
// remove from pds too
- _, err := comatproto.RepoDeleteRecord(r.Context(), client, &comatproto.RepoDeleteRecord_Input{
+ _, err := client.RepoDeleteRecord(r.Context(), &comatproto.RepoDeleteRecord_Input{
Collection: tangled.PublicKeyNSID,
Repo: did,
Rkey: rkey,
diff --git a/appview/state/artifact.go b/appview/state/artifact.go
index 020cba79..8cb629c6 100644
--- a/appview/state/artifact.go
+++ b/appview/state/artifact.go
@@ -22,7 +22,7 @@ import (
// TODO: proper statuses here on early exit
func (s *State) AttachArtifact(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
tagParam := chi.URLParam(r, "tag")
f, err := s.fullyResolvedRepo(r)
if err != nil {
@@ -46,9 +46,14 @@ func (s *State) AttachArtifact(w http.ResponseWriter, r *http.Request) {
}
defer file.Close()
- client, _ := s.auth.AuthorizedClient(r)
+ client, err := s.oauth.AuthorizedClient(r)
+ if err != nil {
+ log.Println("failed to get authorized client", err)
+ s.pages.Notice(w, "upload", "failed to get authorized client")
+ return
+ }
- uploadBlobResp, err := comatproto.RepoUploadBlob(r.Context(), client, file)
+ uploadBlobResp, err := client.RepoUploadBlob(r.Context(), file)
if err != nil {
log.Println("failed to upload blob", err)
s.pages.Notice(w, "upload", "Failed to upload blob to your PDS. Try again later.")
@@ -60,7 +65,7 @@ func (s *State) AttachArtifact(w http.ResponseWriter, r *http.Request) {
rkey := appview.TID()
createdAt := time.Now()
- putRecordResp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
+ putRecordResp, err := client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
Collection: tangled.RepoArtifactNSID,
Repo: user.Did,
Rkey: rkey,
@@ -140,7 +145,11 @@ func (s *State) DownloadArtifact(w http.ResponseWriter, r *http.Request) {
return
}
- client, _ := s.auth.AuthorizedClient(r)
+ client, err := s.oauth.AuthorizedClient(r)
+ if err != nil {
+ log.Println("failed to get authorized client", err)
+ return
+ }
artifacts, err := db.GetArtifact(
s.db,
@@ -159,7 +168,7 @@ func (s *State) DownloadArtifact(w http.ResponseWriter, r *http.Request) {
artifact := artifacts[0]
- getBlobResp, err := comatproto.SyncGetBlob(r.Context(), client, artifact.BlobCid.String(), artifact.Did)
+ getBlobResp, err := client.SyncGetBlob(r.Context(), artifact.BlobCid.String(), artifact.Did)
if err != nil {
log.Println("failed to get blob from pds", err)
return
@@ -171,7 +180,7 @@ func (s *State) DownloadArtifact(w http.ResponseWriter, r *http.Request) {
// TODO: proper statuses here on early exit
func (s *State) DeleteArtifact(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
tagParam := chi.URLParam(r, "tag")
filename := chi.URLParam(r, "file")
f, err := s.fullyResolvedRepo(r)
@@ -180,7 +189,7 @@ func (s *State) DeleteArtifact(w http.ResponseWriter, r *http.Request) {
return
}
- client, _ := s.auth.AuthorizedClient(r)
+ client, _ := s.oauth.AuthorizedClient(r)
tag := plumbing.NewHash(tagParam)
@@ -208,7 +217,7 @@ func (s *State) DeleteArtifact(w http.ResponseWriter, r *http.Request) {
return
}
- _, err = comatproto.RepoDeleteRecord(r.Context(), client, &comatproto.RepoDeleteRecord_Input{
+ _, err = client.RepoDeleteRecord(r.Context(), &comatproto.RepoDeleteRecord_Input{
Collection: tangled.RepoArtifactNSID,
Repo: user.Did,
Rkey: artifact.Rkey,
@@ -254,7 +263,7 @@ func (s *State) resolveTag(f *FullyResolvedRepo, tagParam string) (*types.TagRef
return nil, err
}
- us, err := NewUnsignedClient(f.Knot, s.config.Dev)
+ us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
if err != nil {
return nil, err
}
diff --git a/appview/state/follow.go b/appview/state/follow.go
index 74b5f5a3..4a99f8bd 100644
--- a/appview/state/follow.go
+++ b/appview/state/follow.go
@@ -14,7 +14,7 @@ import (
)
func (s *State) Follow(w http.ResponseWriter, r *http.Request) {
- currentUser := s.auth.GetUser(r)
+ currentUser := s.oauth.GetUser(r)
subject := r.URL.Query().Get("subject")
if subject == "" {
@@ -32,13 +32,17 @@ func (s *State) Follow(w http.ResponseWriter, r *http.Request) {
return
}
- client, _ := s.auth.AuthorizedClient(r)
+ client, err := s.oauth.AuthorizedClient(r)
+ if err != nil {
+ log.Println("failed to authorize client")
+ return
+ }
switch r.Method {
case http.MethodPost:
createdAt := time.Now().Format(time.RFC3339)
rkey := appview.TID()
- resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
+ resp, err := client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
Collection: tangled.GraphFollowNSID,
Repo: currentUser.Did,
Rkey: rkey,
@@ -75,7 +79,7 @@ func (s *State) Follow(w http.ResponseWriter, r *http.Request) {
return
}
- _, err = comatproto.RepoDeleteRecord(r.Context(), client, &comatproto.RepoDeleteRecord_Input{
+ _, err = client.RepoDeleteRecord(r.Context(), &comatproto.RepoDeleteRecord_Input{
Collection: tangled.GraphFollowNSID,
Repo: currentUser.Did,
Rkey: follow.Rkey,
diff --git a/appview/state/git_http.go b/appview/state/git_http.go
index d9296fb0..8f0a0238 100644
--- a/appview/state/git_http.go
+++ b/appview/state/git_http.go
@@ -15,7 +15,7 @@ func (s *State) InfoRefs(w http.ResponseWriter, r *http.Request) {
repo := chi.URLParam(r, "repo")
scheme := "https"
- if s.config.Dev {
+ if s.config.Core.Dev {
scheme = "http"
}
targetURL := fmt.Sprintf("%s://%s/%s/%s/info/refs?%s", scheme, knot, user.DID, repo, r.URL.RawQuery)
@@ -52,7 +52,7 @@ func (s *State) UploadPack(w http.ResponseWriter, r *http.Request) {
repo := chi.URLParam(r, "repo")
scheme := "https"
- if s.config.Dev {
+ if s.config.Core.Dev {
scheme = "http"
}
targetURL := fmt.Sprintf("%s://%s/%s/%s/git-upload-pack?%s", scheme, knot, user.DID, repo, r.URL.RawQuery)
diff --git a/appview/state/middleware.go b/appview/state/middleware.go
index c3c5cdbe..1baabcf1 100644
--- a/appview/state/middleware.go
+++ b/appview/state/middleware.go
@@ -20,7 +20,7 @@ func knotRoleMiddleware(s *State, group string) middleware.Middleware {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// requires auth also
- actor := s.auth.GetUser(r)
+ actor := s.oauth.GetUser(r)
if actor == nil {
// we need a logged in user
log.Printf("not logged in, redirecting")
@@ -54,7 +54,7 @@ func RepoPermissionMiddleware(s *State, requiredPerm string) middleware.Middlewa
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// requires auth also
- actor := s.auth.GetUser(r)
+ actor := s.oauth.GetUser(r)
if actor == nil {
// we need a logged in user
log.Printf("not logged in, redirecting")
diff --git a/appview/state/profile.go b/appview/state/profile.go
index a5c3fc63..ebec4531 100644
--- a/appview/state/profile.go
+++ b/appview/state/profile.go
@@ -119,7 +119,7 @@ func (s *State) profilePage(w http.ResponseWriter, r *http.Request) {
log.Printf("getting follow stats repos for %s: %s", ident.DID.String(), err)
}
- loggedInUser := s.auth.GetUser(r)
+ loggedInUser := s.oauth.GetUser(r)
followStatus := db.IsNotFollowing
if loggedInUser != nil {
followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, ident.DID.String())
@@ -161,7 +161,7 @@ func (s *State) reposPage(w http.ResponseWriter, r *http.Request) {
log.Printf("getting repos for %s: %s", ident.DID.String(), err)
}
- loggedInUser := s.auth.GetUser(r)
+ loggedInUser := s.oauth.GetUser(r)
followStatus := db.IsNotFollowing
if loggedInUser != nil {
followStatus = db.GetFollowStatus(s.db, loggedInUser.Did, ident.DID.String())
@@ -190,15 +190,15 @@ func (s *State) reposPage(w http.ResponseWriter, r *http.Request) {
}
func (s *State) GetAvatarUri(handle string) string {
- secret := s.config.AvatarSharedSecret
+ secret := s.config.Avatar.SharedSecret
h := hmac.New(sha256.New, []byte(secret))
h.Write([]byte(handle))
signature := hex.EncodeToString(h.Sum(nil))
- return fmt.Sprintf("%s/%s/%s", s.config.AvatarHost, signature, handle)
+ return fmt.Sprintf("%s/%s/%s", s.config.Avatar.Host, signature, handle)
}
func (s *State) UpdateProfileBio(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
err := r.ParseForm()
if err != nil {
@@ -246,7 +246,7 @@ func (s *State) UpdateProfileBio(w http.ResponseWriter, r *http.Request) {
}
func (s *State) UpdateProfilePins(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
err := r.ParseForm()
if err != nil {
@@ -286,7 +286,7 @@ func (s *State) UpdateProfilePins(w http.ResponseWriter, r *http.Request) {
}
func (s *State) updateProfile(profile *db.Profile, w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
tx, err := s.db.BeginTx(r.Context(), nil)
if err != nil {
log.Println("failed to start transaction", err)
@@ -294,7 +294,12 @@ func (s *State) updateProfile(profile *db.Profile, w http.ResponseWriter, r *htt
return
}
- client, _ := s.auth.AuthorizedClient(r)
+ client, err := s.oauth.AuthorizedClient(r)
+ if err != nil {
+ log.Println("failed to get authorized client", err)
+ s.pages.Notice(w, "update-profile", "Failed to update profile, try again later.")
+ return
+ }
// yeah... lexgen dose not support syntax.ATURI in the record for some reason,
// nor does it support exact size arrays
@@ -308,13 +313,13 @@ func (s *State) updateProfile(profile *db.Profile, w http.ResponseWriter, r *htt
vanityStats = append(vanityStats, string(v.Kind))
}
- ex, _ := comatproto.RepoGetRecord(r.Context(), client, "", tangled.ActorProfileNSID, user.Did, "self")
+ ex, _ := client.RepoGetRecord(r.Context(), "", tangled.ActorProfileNSID, user.Did, "self")
var cid *string
if ex != nil {
cid = ex.Cid
}
- _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
+ _, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
Collection: tangled.ActorProfileNSID,
Repo: user.Did,
Rkey: "self",
@@ -347,7 +352,7 @@ func (s *State) updateProfile(profile *db.Profile, w http.ResponseWriter, r *htt
}
func (s *State) EditBioFragment(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
profile, err := db.GetProfile(s.db, user.Did)
if err != nil {
@@ -361,7 +366,7 @@ func (s *State) EditBioFragment(w http.ResponseWriter, r *http.Request) {
}
func (s *State) EditPinsFragment(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
profile, err := db.GetProfile(s.db, user.Did)
if err != nil {
diff --git a/appview/state/pull.go b/appview/state/pull.go
index db6667dc..7a08b697 100644
--- a/appview/state/pull.go
+++ b/appview/state/pull.go
@@ -13,8 +13,8 @@ import (
"tangled.sh/tangled.sh/core/api/tangled"
"tangled.sh/tangled.sh/core/appview"
- "tangled.sh/tangled.sh/core/appview/auth"
"tangled.sh/tangled.sh/core/appview/db"
+ "tangled.sh/tangled.sh/core/appview/oauth"
"tangled.sh/tangled.sh/core/appview/pages"
"tangled.sh/tangled.sh/core/patchutil"
"tangled.sh/tangled.sh/core/types"
@@ -29,7 +29,7 @@ import (
func (s *State) PullActions(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
f, err := s.fullyResolvedRepo(r)
if err != nil {
log.Println("failed to get repo and knot", err)
@@ -73,7 +73,7 @@ func (s *State) PullActions(w http.ResponseWriter, r *http.Request) {
}
func (s *State) RepoSinglePull(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
f, err := s.fullyResolvedRepo(r)
if err != nil {
log.Println("failed to get repo and knot", err)
@@ -143,7 +143,7 @@ func (s *State) mergeCheck(f *FullyResolvedRepo, pull *db.Pull) types.MergeCheck
}
}
- ksClient, err := NewSignedClient(f.Knot, secret, s.config.Dev)
+ ksClient, err := NewSignedClient(f.Knot, secret, s.config.Core.Dev)
if err != nil {
log.Printf("failed to setup signed client for %s; ignoring: %v", f.Knot, err)
return types.MergeCheckResponse{
@@ -215,7 +215,7 @@ func (s *State) resubmitCheck(f *FullyResolvedRepo, pull *db.Pull) pages.Resubmi
repoName = f.RepoName
}
- us, err := NewUnsignedClient(knot, s.config.Dev)
+ us, err := NewUnsignedClient(knot, s.config.Core.Dev)
if err != nil {
log.Printf("failed to setup client for %s; ignoring: %v", knot, err)
return pages.Unknown
@@ -250,7 +250,7 @@ func (s *State) resubmitCheck(f *FullyResolvedRepo, pull *db.Pull) pages.Resubmi
}
func (s *State) RepoPullPatch(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
f, err := s.fullyResolvedRepo(r)
if err != nil {
log.Println("failed to get repo and knot", err)
@@ -298,7 +298,7 @@ func (s *State) RepoPullPatch(w http.ResponseWriter, r *http.Request) {
}
func (s *State) RepoPullInterdiff(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
f, err := s.fullyResolvedRepo(r)
if err != nil {
@@ -355,7 +355,7 @@ func (s *State) RepoPullInterdiff(w http.ResponseWriter, r *http.Request) {
interdiff := patchutil.Interdiff(previousPatch, currentPatch)
s.pages.RepoPullInterdiffPage(w, pages.RepoPullInterdiffParams{
- LoggedInUser: s.auth.GetUser(r),
+ LoggedInUser: s.oauth.GetUser(r),
RepoInfo: f.RepoInfo(s, user),
Pull: pull,
Round: roundIdInt,
@@ -397,7 +397,7 @@ func (s *State) RepoPullPatchRaw(w http.ResponseWriter, r *http.Request) {
}
func (s *State) RepoPulls(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
params := r.URL.Query()
state := db.PullOpen
@@ -451,7 +451,7 @@ func (s *State) RepoPulls(w http.ResponseWriter, r *http.Request) {
}
s.pages.RepoPulls(w, pages.RepoPullsParams{
- LoggedInUser: s.auth.GetUser(r),
+ LoggedInUser: s.oauth.GetUser(r),
RepoInfo: f.RepoInfo(s, user),
Pulls: pulls,
DidHandleMap: didHandleMap,
@@ -461,7 +461,7 @@ func (s *State) RepoPulls(w http.ResponseWriter, r *http.Request) {
}
func (s *State) PullComment(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
f, err := s.fullyResolvedRepo(r)
if err != nil {
log.Println("failed to get repo and knot", err)
@@ -519,8 +519,13 @@ func (s *State) PullComment(w http.ResponseWriter, r *http.Request) {
}
atUri := f.RepoAt.String()
- client, _ := s.auth.AuthorizedClient(r)
- atResp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
+ client, err := s.oauth.AuthorizedClient(r)
+ if err != nil {
+ log.Println("failed to get authorized client", err)
+ s.pages.Notice(w, "pull-comment", "Failed to create comment.")
+ return
+ }
+ atResp, err := client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
Collection: tangled.RepoPullCommentNSID,
Repo: user.Did,
Rkey: appview.TID(),
@@ -568,7 +573,7 @@ func (s *State) PullComment(w http.ResponseWriter, r *http.Request) {
}
func (s *State) NewPull(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
f, err := s.fullyResolvedRepo(r)
if err != nil {
log.Println("failed to get repo and knot", err)
@@ -577,7 +582,7 @@ func (s *State) NewPull(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
- us, err := NewUnsignedClient(f.Knot, s.config.Dev)
+ us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
if err != nil {
log.Printf("failed to create unsigned client for %s", f.Knot)
s.pages.Error503(w)
@@ -646,7 +651,7 @@ func (s *State) NewPull(w http.ResponseWriter, r *http.Request) {
return
}
- us, err := NewUnsignedClient(f.Knot, s.config.Dev)
+ us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
if err != nil {
log.Printf("failed to create unsigned client to %s: %v", f.Knot, err)
s.pages.Notice(w, "pull", "Failed to create a pull request. Try again later.")
@@ -689,7 +694,7 @@ func (s *State) NewPull(w http.ResponseWriter, r *http.Request) {
}
}
-func (s *State) handleBranchBasedPull(w http.ResponseWriter, r *http.Request, f *FullyResolvedRepo, user *auth.User, title, body, targetBranch, sourceBranch string) {
+func (s *State) handleBranchBasedPull(w http.ResponseWriter, r *http.Request, f *FullyResolvedRepo, user *oauth.User, title, body, targetBranch, sourceBranch string) {
pullSource := &db.PullSource{
Branch: sourceBranch,
}
@@ -698,7 +703,7 @@ func (s *State) handleBranchBasedPull(w http.ResponseWriter, r *http.Request, f
}
// Generate a patch using /compare
- ksClient, err := NewUnsignedClient(f.Knot, s.config.Dev)
+ ksClient, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
if err != nil {
log.Printf("failed to create signed client for %s: %s", f.Knot, err)
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
@@ -723,7 +728,7 @@ func (s *State) handleBranchBasedPull(w http.ResponseWriter, r *http.Request, f
s.createPullRequest(w, r, f, user, title, body, targetBranch, patch, sourceRev, pullSource, recordPullSource)
}
-func (s *State) handlePatchBasedPull(w http.ResponseWriter, r *http.Request, f *FullyResolvedRepo, user *auth.User, title, body, targetBranch, patch string) {
+func (s *State) handlePatchBasedPull(w http.ResponseWriter, r *http.Request, f *FullyResolvedRepo, user *oauth.User, title, body, targetBranch, patch string) {
if !patchutil.IsPatchValid(patch) {
s.pages.Notice(w, "pull", "Invalid patch format. Please provide a valid diff.")
return
@@ -732,7 +737,7 @@ func (s *State) handlePatchBasedPull(w http.ResponseWriter, r *http.Request, f *
s.createPullRequest(w, r, f, user, title, body, targetBranch, patch, "", nil, nil)
}
-func (s *State) handleForkBasedPull(w http.ResponseWriter, r *http.Request, f *FullyResolvedRepo, user *auth.User, forkRepo string, title, body, targetBranch, sourceBranch string) {
+func (s *State) handleForkBasedPull(w http.ResponseWriter, r *http.Request, f *FullyResolvedRepo, user *oauth.User, forkRepo string, title, body, targetBranch, sourceBranch string) {
fork, err := db.GetForkByDid(s.db, user.Did, forkRepo)
if errors.Is(err, sql.ErrNoRows) {
s.pages.Notice(w, "pull", "No such fork.")
@@ -750,14 +755,14 @@ func (s *State) handleForkBasedPull(w http.ResponseWriter, r *http.Request, f *F
return
}
- sc, err := NewSignedClient(fork.Knot, secret, s.config.Dev)
+ sc, err := NewSignedClient(fork.Knot, secret, s.config.Core.Dev)
if err != nil {
log.Println("failed to create signed client:", err)
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
return
}
- us, err := NewUnsignedClient(fork.Knot, s.config.Dev)
+ us, err := NewUnsignedClient(fork.Knot, s.config.Core.Dev)
if err != nil {
log.Println("failed to create unsigned client:", err)
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
@@ -816,7 +821,7 @@ func (s *State) createPullRequest(
w http.ResponseWriter,
r *http.Request,
f *FullyResolvedRepo,
- user *auth.User,
+ user *oauth.User,
title, body, targetBranch string,
patch string,
sourceRev string,
@@ -870,7 +875,12 @@ func (s *State) createPullRequest(
s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
return
}
- client, _ := s.auth.AuthorizedClient(r)
+ client, err := s.oauth.AuthorizedClient(r)
+ if err != nil {
+ log.Println("failed to get authorized client", err)
+ s.pages.Notice(w, "pull", "Failed to create pull request. Try again later.")
+ return
+ }
pullId, err := db.NextPullId(s.db, f.RepoAt)
if err != nil {
log.Println("failed to get pull id", err)
@@ -878,7 +888,7 @@ func (s *State) createPullRequest(
return
}
- _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
+ _, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
Collection: tangled.RepoPullNSID,
Repo: user.Did,
Rkey: rkey,
@@ -929,7 +939,7 @@ func (s *State) ValidatePatch(w http.ResponseWriter, r *http.Request) {
}
func (s *State) PatchUploadFragment(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
f, err := s.fullyResolvedRepo(r)
if err != nil {
log.Println("failed to get repo and knot", err)
@@ -942,14 +952,14 @@ func (s *State) PatchUploadFragment(w http.ResponseWriter, r *http.Request) {
}
func (s *State) CompareBranchesFragment(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
f, err := s.fullyResolvedRepo(r)
if err != nil {
log.Println("failed to get repo and knot", err)
return
}
- us, err := NewUnsignedClient(f.Knot, s.config.Dev)
+ us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
if err != nil {
log.Printf("failed to create unsigned client for %s", f.Knot)
s.pages.Error503(w)
@@ -982,7 +992,7 @@ func (s *State) CompareBranchesFragment(w http.ResponseWriter, r *http.Request)
}
func (s *State) CompareForksFragment(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
f, err := s.fullyResolvedRepo(r)
if err != nil {
log.Println("failed to get repo and knot", err)
@@ -1002,7 +1012,7 @@ func (s *State) CompareForksFragment(w http.ResponseWriter, r *http.Request) {
}
func (s *State) CompareForksBranchesFragment(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
f, err := s.fullyResolvedRepo(r)
if err != nil {
@@ -1019,7 +1029,7 @@ func (s *State) CompareForksBranchesFragment(w http.ResponseWriter, r *http.Requ
return
}
- sourceBranchesClient, err := NewUnsignedClient(repo.Knot, s.config.Dev)
+ sourceBranchesClient, err := NewUnsignedClient(repo.Knot, s.config.Core.Dev)
if err != nil {
log.Printf("failed to create unsigned client for %s", repo.Knot)
s.pages.Error503(w)
@@ -1046,7 +1056,7 @@ func (s *State) CompareForksBranchesFragment(w http.ResponseWriter, r *http.Requ
return
}
- targetBranchesClient, err := NewUnsignedClient(f.Knot, s.config.Dev)
+ targetBranchesClient, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
if err != nil {
log.Printf("failed to create unsigned client for target knot %s", f.Knot)
s.pages.Error503(w)
@@ -1081,7 +1091,7 @@ func (s *State) CompareForksBranchesFragment(w http.ResponseWriter, r *http.Requ
}
func (s *State) ResubmitPull(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
f, err := s.fullyResolvedRepo(r)
if err != nil {
log.Println("failed to get repo and knot", err)
@@ -1117,7 +1127,7 @@ func (s *State) ResubmitPull(w http.ResponseWriter, r *http.Request) {
}
func (s *State) resubmitPatch(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
pull, ok := r.Context().Value("pull").(*db.Pull)
if !ok {
@@ -1159,16 +1169,21 @@ func (s *State) resubmitPatch(w http.ResponseWriter, r *http.Request) {
s.pages.Notice(w, "resubmit-error", "Failed to resubmit pull request. Try again later.")
return
}
- client, _ := s.auth.AuthorizedClient(r)
+ client, err := s.oauth.AuthorizedClient(r)
+ if err != nil {
+ log.Println("failed to get authorized client", err)
+ s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
+ return
+ }
- ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoPullNSID, user.Did, pull.Rkey)
+ ex, err := client.RepoGetRecord(r.Context(), "", tangled.RepoPullNSID, user.Did, pull.Rkey)
if err != nil {
// failed to get record
s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.")
return
}
- _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
+ _, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
Collection: tangled.RepoPullNSID,
Repo: user.Did,
Rkey: pull.Rkey,
@@ -1200,7 +1215,7 @@ func (s *State) resubmitPatch(w http.ResponseWriter, r *http.Request) {
}
func (s *State) resubmitBranch(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
pull, ok := r.Context().Value("pull").(*db.Pull)
if !ok {
@@ -1227,7 +1242,7 @@ func (s *State) resubmitBranch(w http.ResponseWriter, r *http.Request) {
return
}
- ksClient, err := NewUnsignedClient(f.Knot, s.config.Dev)
+ ksClient, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
if err != nil {
log.Printf("failed to create client for %s: %s", f.Knot, err)
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
@@ -1268,9 +1283,14 @@ func (s *State) resubmitBranch(w http.ResponseWriter, r *http.Request) {
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
return
}
- client, _ := s.auth.AuthorizedClient(r)
+ client, err := s.oauth.AuthorizedClient(r)
+ if err != nil {
+ log.Println("failed to authorize client")
+ s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
+ return
+ }
- ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoPullNSID, user.Did, pull.Rkey)
+ ex, err := client.RepoGetRecord(r.Context(), "", tangled.RepoPullNSID, user.Did, pull.Rkey)
if err != nil {
// failed to get record
s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.")
@@ -1280,7 +1300,7 @@ func (s *State) resubmitBranch(w http.ResponseWriter, r *http.Request) {
recordPullSource := &tangled.RepoPull_Source{
Branch: pull.PullSource.Branch,
}
- _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
+ _, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
Collection: tangled.RepoPullNSID,
Repo: user.Did,
Rkey: pull.Rkey,
@@ -1313,7 +1333,7 @@ func (s *State) resubmitBranch(w http.ResponseWriter, r *http.Request) {
}
func (s *State) resubmitFork(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
pull, ok := r.Context().Value("pull").(*db.Pull)
if !ok {
@@ -1342,7 +1362,7 @@ func (s *State) resubmitFork(w http.ResponseWriter, r *http.Request) {
}
// extract patch by performing compare
- ksClient, err := NewUnsignedClient(forkRepo.Knot, s.config.Dev)
+ ksClient, err := NewUnsignedClient(forkRepo.Knot, s.config.Core.Dev)
if err != nil {
log.Printf("failed to create client for %s: %s", forkRepo.Knot, err)
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
@@ -1357,7 +1377,7 @@ func (s *State) resubmitFork(w http.ResponseWriter, r *http.Request) {
}
// update the hidden tracking branch to latest
- signedClient, err := NewSignedClient(forkRepo.Knot, secret, s.config.Dev)
+ signedClient, err := NewSignedClient(forkRepo.Knot, secret, s.config.Core.Dev)
if err != nil {
log.Printf("failed to create signed client for %s: %s", forkRepo.Knot, err)
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
@@ -1406,9 +1426,14 @@ func (s *State) resubmitFork(w http.ResponseWriter, r *http.Request) {
s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
return
}
- client, _ := s.auth.AuthorizedClient(r)
+ client, err := s.oauth.AuthorizedClient(r)
+ if err != nil {
+ log.Println("failed to get client")
+ s.pages.Notice(w, "resubmit-error", "Failed to create pull request. Try again later.")
+ return
+ }
- ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoPullNSID, user.Did, pull.Rkey)
+ ex, err := client.RepoGetRecord(r.Context(), "", tangled.RepoPullNSID, user.Did, pull.Rkey)
if err != nil {
// failed to get record
s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.")
@@ -1420,7 +1445,7 @@ func (s *State) resubmitFork(w http.ResponseWriter, r *http.Request) {
Branch: pull.PullSource.Branch,
Repo: &repoAt,
}
- _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
+ _, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
Collection: tangled.RepoPullNSID,
Repo: user.Did,
Rkey: pull.Rkey,
@@ -1503,7 +1528,7 @@ func (s *State) MergePull(w http.ResponseWriter, r *http.Request) {
log.Printf("failed to get primary email: %s", err)
}
- ksClient, err := NewSignedClient(f.Knot, secret, s.config.Dev)
+ ksClient, err := NewSignedClient(f.Knot, secret, s.config.Core.Dev)
if err != nil {
log.Printf("failed to create signed client for %s: %s", f.Knot, err)
s.pages.Notice(w, "pull-merge-error", "Failed to merge pull request. Try again later.")
@@ -1533,7 +1558,7 @@ func (s *State) MergePull(w http.ResponseWriter, r *http.Request) {
}
func (s *State) ClosePull(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
f, err := s.fullyResolvedRepo(r)
if err != nil {
@@ -1587,7 +1612,7 @@ func (s *State) ClosePull(w http.ResponseWriter, r *http.Request) {
}
func (s *State) ReopenPull(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
f, err := s.fullyResolvedRepo(r)
if err != nil {
diff --git a/appview/state/repo.go b/appview/state/repo.go
index 6a85925f..9c0fa296 100644
--- a/appview/state/repo.go
+++ b/appview/state/repo.go
@@ -18,8 +18,8 @@ import (
"tangled.sh/tangled.sh/core/api/tangled"
"tangled.sh/tangled.sh/core/appview"
- "tangled.sh/tangled.sh/core/appview/auth"
"tangled.sh/tangled.sh/core/appview/db"
+ "tangled.sh/tangled.sh/core/appview/oauth"
"tangled.sh/tangled.sh/core/appview/pages"
"tangled.sh/tangled.sh/core/appview/pages/markup"
"tangled.sh/tangled.sh/core/appview/pages/repoinfo"
@@ -45,7 +45,7 @@ func (s *State) RepoIndex(w http.ResponseWriter, r *http.Request) {
return
}
- us, err := NewUnsignedClient(f.Knot, s.config.Dev)
+ us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
if err != nil {
log.Printf("failed to create unsigned client for %s", f.Knot)
s.pages.Error503(w)
@@ -119,7 +119,7 @@ func (s *State) RepoIndex(w http.ResponseWriter, r *http.Request) {
emails := uniqueEmails(commitsTrunc)
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
s.pages.RepoIndexPage(w, pages.RepoIndexParams{
LoggedInUser: user,
RepoInfo: f.RepoInfo(s, user),
@@ -150,7 +150,7 @@ func (s *State) RepoLog(w http.ResponseWriter, r *http.Request) {
ref := chi.URLParam(r, "ref")
- us, err := NewUnsignedClient(f.Knot, s.config.Dev)
+ us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
if err != nil {
log.Println("failed to create unsigned client", err)
return
@@ -190,7 +190,7 @@ func (s *State) RepoLog(w http.ResponseWriter, r *http.Request) {
tagMap[hash] = append(tagMap[hash], tag.Name)
}
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
s.pages.RepoLog(w, pages.RepoLogParams{
LoggedInUser: user,
TagMap: tagMap,
@@ -209,7 +209,7 @@ func (s *State) RepoDescriptionEdit(w http.ResponseWriter, r *http.Request) {
return
}
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
s.pages.EditRepoDescriptionFragment(w, pages.RepoDescriptionParams{
RepoInfo: f.RepoInfo(s, user),
})
@@ -232,7 +232,7 @@ func (s *State) RepoDescription(w http.ResponseWriter, r *http.Request) {
return
}
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
switch r.Method {
case http.MethodGet:
@@ -241,9 +241,14 @@ func (s *State) RepoDescription(w http.ResponseWriter, r *http.Request) {
})
return
case http.MethodPut:
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
newDescription := r.FormValue("description")
- client, _ := s.auth.AuthorizedClient(r)
+ client, err := s.oauth.AuthorizedClient(r)
+ if err != nil {
+ log.Println("failed to get client")
+ s.pages.Notice(w, "repo-notice", "Failed to update description, try again later.")
+ return
+ }
// optimistic update
err = db.UpdateDescription(s.db, string(repoAt), newDescription)
@@ -256,13 +261,13 @@ func (s *State) RepoDescription(w http.ResponseWriter, r *http.Request) {
// this is a bit of a pain because the golang atproto impl does not allow nil SwapRecord field
//
// SwapRecord is optional and should happen automagically, but given that it does not, we have to perform two requests
- ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoNSID, user.Did, rkey)
+ ex, err := client.RepoGetRecord(r.Context(), "", tangled.RepoNSID, user.Did, rkey)
if err != nil {
// failed to get record
s.pages.Notice(w, "repo-notice", "Failed to update description, no record found on PDS.")
return
}
- _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
+ _, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
Collection: tangled.RepoNSID,
Repo: user.Did,
Rkey: rkey,
@@ -303,7 +308,7 @@ func (s *State) RepoCommit(w http.ResponseWriter, r *http.Request) {
}
ref := chi.URLParam(r, "ref")
protocol := "http"
- if !s.config.Dev {
+ if !s.config.Core.Dev {
protocol = "https"
}
@@ -331,7 +336,7 @@ func (s *State) RepoCommit(w http.ResponseWriter, r *http.Request) {
return
}
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
s.pages.RepoCommit(w, pages.RepoCommitParams{
LoggedInUser: user,
RepoInfo: f.RepoInfo(s, user),
@@ -351,7 +356,7 @@ func (s *State) RepoTree(w http.ResponseWriter, r *http.Request) {
ref := chi.URLParam(r, "ref")
treePath := chi.URLParam(r, "*")
protocol := "http"
- if !s.config.Dev {
+ if !s.config.Core.Dev {
protocol = "https"
}
resp, err := http.Get(fmt.Sprintf("%s://%s/%s/%s/tree/%s/%s", protocol, f.Knot, f.OwnerDid(), f.RepoName, ref, treePath))
@@ -380,7 +385,7 @@ func (s *State) RepoTree(w http.ResponseWriter, r *http.Request) {
return
}
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
var breadcrumbs [][]string
breadcrumbs = append(breadcrumbs, []string{f.RepoName, fmt.Sprintf("/%s/tree/%s", f.OwnerSlashRepo(), ref)})
@@ -411,7 +416,7 @@ func (s *State) RepoTags(w http.ResponseWriter, r *http.Request) {
return
}
- us, err := NewUnsignedClient(f.Knot, s.config.Dev)
+ us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
if err != nil {
log.Println("failed to create unsigned client", err)
return
@@ -451,7 +456,7 @@ func (s *State) RepoTags(w http.ResponseWriter, r *http.Request) {
}
}
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
s.pages.RepoTags(w, pages.RepoTagsParams{
LoggedInUser: user,
RepoInfo: f.RepoInfo(s, user),
@@ -469,7 +474,7 @@ func (s *State) RepoBranches(w http.ResponseWriter, r *http.Request) {
return
}
- us, err := NewUnsignedClient(f.Knot, s.config.Dev)
+ us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
if err != nil {
log.Println("failed to create unsigned client", err)
return
@@ -511,7 +516,7 @@ func (s *State) RepoBranches(w http.ResponseWriter, r *http.Request) {
return strings.Compare(a.Name, b.Name) * -1
})
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
s.pages.RepoBranches(w, pages.RepoBranchesParams{
LoggedInUser: user,
RepoInfo: f.RepoInfo(s, user),
@@ -530,7 +535,7 @@ func (s *State) RepoBlob(w http.ResponseWriter, r *http.Request) {
ref := chi.URLParam(r, "ref")
filePath := chi.URLParam(r, "*")
protocol := "http"
- if !s.config.Dev {
+ if !s.config.Core.Dev {
protocol = "https"
}
resp, err := http.Get(fmt.Sprintf("%s://%s/%s/%s/blob/%s/%s", protocol, f.Knot, f.OwnerDid(), f.RepoName, ref, filePath))
@@ -568,7 +573,7 @@ func (s *State) RepoBlob(w http.ResponseWriter, r *http.Request) {
showRendered = r.URL.Query().Get("code") != "true"
}
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
s.pages.RepoBlob(w, pages.RepoBlobParams{
LoggedInUser: user,
RepoInfo: f.RepoInfo(s, user),
@@ -591,7 +596,7 @@ func (s *State) RepoBlobRaw(w http.ResponseWriter, r *http.Request) {
filePath := chi.URLParam(r, "*")
protocol := "http"
- if !s.config.Dev {
+ if !s.config.Core.Dev {
protocol = "https"
}
resp, err := http.Get(fmt.Sprintf("%s://%s/%s/%s/blob/%s/%s", protocol, f.Knot, f.OwnerDid(), f.RepoName, ref, filePath))
@@ -652,7 +657,7 @@ func (s *State) AddCollaborator(w http.ResponseWriter, r *http.Request) {
return
}
- ksClient, err := NewSignedClient(f.Knot, secret, s.config.Dev)
+ ksClient, err := NewSignedClient(f.Knot, secret, s.config.Core.Dev)
if err != nil {
log.Println("failed to create client to ", f.Knot)
return
@@ -714,7 +719,7 @@ func (s *State) AddCollaborator(w http.ResponseWriter, r *http.Request) {
}
func (s *State) DeleteRepo(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
f, err := s.fullyResolvedRepo(r)
if err != nil {
@@ -723,9 +728,13 @@ func (s *State) DeleteRepo(w http.ResponseWriter, r *http.Request) {
}
// remove record from pds
- xrpcClient, _ := s.auth.AuthorizedClient(r)
+ xrpcClient, err := s.oauth.AuthorizedClient(r)
+ if err != nil {
+ log.Println("failed to get authorized client", err)
+ return
+ }
repoRkey := f.RepoAt.RecordKey().String()
- _, err = comatproto.RepoDeleteRecord(r.Context(), xrpcClient, &comatproto.RepoDeleteRecord_Input{
+ _, err = xrpcClient.RepoDeleteRecord(r.Context(), &comatproto.RepoDeleteRecord_Input{
Collection: tangled.RepoNSID,
Repo: user.Did,
Rkey: repoRkey,
@@ -743,7 +752,7 @@ func (s *State) DeleteRepo(w http.ResponseWriter, r *http.Request) {
return
}
- ksClient, err := NewSignedClient(f.Knot, secret, s.config.Dev)
+ ksClient, err := NewSignedClient(f.Knot, secret, s.config.Core.Dev)
if err != nil {
log.Println("failed to create client to ", f.Knot)
return
@@ -838,7 +847,7 @@ func (s *State) SetDefaultBranch(w http.ResponseWriter, r *http.Request) {
return
}
- ksClient, err := NewSignedClient(f.Knot, secret, s.config.Dev)
+ ksClient, err := NewSignedClient(f.Knot, secret, s.config.Core.Dev)
if err != nil {
log.Println("failed to create client to ", f.Knot)
return
@@ -868,7 +877,7 @@ func (s *State) RepoSettings(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
// for now, this is just pubkeys
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
repoCollaborators, err := f.Collaborators(r.Context(), s)
if err != nil {
log.Println("failed to get collaborators", err)
@@ -884,7 +893,7 @@ func (s *State) RepoSettings(w http.ResponseWriter, r *http.Request) {
var branchNames []string
var defaultBranch string
- us, err := NewUnsignedClient(f.Knot, s.config.Dev)
+ us, err := NewUnsignedClient(f.Knot, s.config.Core.Dev)
if err != nil {
log.Println("failed to create unsigned client", err)
} else {
@@ -1008,7 +1017,7 @@ func (f *FullyResolvedRepo) Collaborators(ctx context.Context, s *State) ([]page
return collaborators, nil
}
-func (f *FullyResolvedRepo) RepoInfo(s *State, u *auth.User) repoinfo.RepoInfo {
+func (f *FullyResolvedRepo) RepoInfo(s *State, u *oauth.User) repoinfo.RepoInfo {
isStarred := false
if u != nil {
isStarred = db.GetStarStatus(s.db, u.Did, syntax.ATURI(f.RepoAt))
@@ -1051,7 +1060,7 @@ func (f *FullyResolvedRepo) RepoInfo(s *State, u *auth.User) repoinfo.RepoInfo {
knot := f.Knot
var disableFork bool
- us, err := NewUnsignedClient(knot, s.config.Dev)
+ us, err := NewUnsignedClient(knot, s.config.Core.Dev)
if err != nil {
log.Printf("failed to create unsigned client for %s: %v", knot, err)
} else {
@@ -1105,7 +1114,7 @@ func (f *FullyResolvedRepo) RepoInfo(s *State, u *auth.User) repoinfo.RepoInfo {
}
func (s *State) RepoSingleIssue(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
f, err := s.fullyResolvedRepo(r)
if err != nil {
log.Println("failed to get repo and knot", err)
@@ -1159,7 +1168,7 @@ func (s *State) RepoSingleIssue(w http.ResponseWriter, r *http.Request) {
}
func (s *State) CloseIssue(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
f, err := s.fullyResolvedRepo(r)
if err != nil {
log.Println("failed to get repo and knot", err)
@@ -1195,8 +1204,12 @@ func (s *State) CloseIssue(w http.ResponseWriter, r *http.Request) {
closed := tangled.RepoIssueStateClosed
- client, _ := s.auth.AuthorizedClient(r)
- _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
+ client, err := s.oauth.AuthorizedClient(r)
+ if err != nil {
+ log.Println("failed to get authorized client", err)
+ return
+ }
+ _, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
Collection: tangled.RepoIssueStateNSID,
Repo: user.Did,
Rkey: appview.TID(),
@@ -1214,7 +1227,7 @@ func (s *State) CloseIssue(w http.ResponseWriter, r *http.Request) {
return
}
- err := db.CloseIssue(s.db, f.RepoAt, issueIdInt)
+ err = db.CloseIssue(s.db, f.RepoAt, issueIdInt)
if err != nil {
log.Println("failed to close issue", err)
s.pages.Notice(w, "issue-action", "Failed to close issue. Try again later.")
@@ -1231,7 +1244,7 @@ func (s *State) CloseIssue(w http.ResponseWriter, r *http.Request) {
}
func (s *State) ReopenIssue(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
f, err := s.fullyResolvedRepo(r)
if err != nil {
log.Println("failed to get repo and knot", err)
@@ -1279,7 +1292,7 @@ func (s *State) ReopenIssue(w http.ResponseWriter, r *http.Request) {
}
func (s *State) NewIssueComment(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
f, err := s.fullyResolvedRepo(r)
if err != nil {
log.Println("failed to get repo and knot", err)
@@ -1330,8 +1343,13 @@ func (s *State) NewIssueComment(w http.ResponseWriter, r *http.Request) {
}
atUri := f.RepoAt.String()
- client, _ := s.auth.AuthorizedClient(r)
- _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
+ client, err := s.oauth.AuthorizedClient(r)
+ if err != nil {
+ log.Println("failed to get authorized client", err)
+ s.pages.Notice(w, "issue-comment", "Failed to create comment.")
+ return
+ }
+ _, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
Collection: tangled.RepoIssueCommentNSID,
Repo: user.Did,
Rkey: rkey,
@@ -1358,7 +1376,7 @@ func (s *State) NewIssueComment(w http.ResponseWriter, r *http.Request) {
}
func (s *State) IssueComment(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
f, err := s.fullyResolvedRepo(r)
if err != nil {
log.Println("failed to get repo and knot", err)
@@ -1417,7 +1435,7 @@ func (s *State) IssueComment(w http.ResponseWriter, r *http.Request) {
}
func (s *State) EditIssueComment(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
f, err := s.fullyResolvedRepo(r)
if err != nil {
log.Println("failed to get repo and knot", err)
@@ -1469,7 +1487,12 @@ func (s *State) EditIssueComment(w http.ResponseWriter, r *http.Request) {
case http.MethodPost:
// extract form value
newBody := r.FormValue("body")
- client, _ := s.auth.AuthorizedClient(r)
+ client, err := s.oauth.AuthorizedClient(r)
+ if err != nil {
+ log.Println("failed to get authorized client", err)
+ s.pages.Notice(w, "issue-comment", "Failed to create comment.")
+ return
+ }
rkey := comment.Rkey
// optimistic update
@@ -1484,7 +1507,7 @@ func (s *State) EditIssueComment(w http.ResponseWriter, r *http.Request) {
// rkey is optional, it was introduced later
if comment.Rkey != "" {
// update the record on pds
- ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoIssueCommentNSID, user.Did, rkey)
+ ex, err := client.RepoGetRecord(r.Context(), "", tangled.RepoIssueCommentNSID, user.Did, rkey)
if err != nil {
// failed to get record
log.Println(err, rkey)
@@ -1499,7 +1522,7 @@ func (s *State) EditIssueComment(w http.ResponseWriter, r *http.Request) {
createdAt := record["createdAt"].(string)
commentIdInt64 := int64(commentIdInt)
- _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
+ _, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
Collection: tangled.RepoIssueCommentNSID,
Repo: user.Did,
Rkey: rkey,
@@ -1542,7 +1565,7 @@ func (s *State) EditIssueComment(w http.ResponseWriter, r *http.Request) {
}
func (s *State) DeleteIssueComment(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
f, err := s.fullyResolvedRepo(r)
if err != nil {
log.Println("failed to get repo and knot", err)
@@ -1599,8 +1622,13 @@ func (s *State) DeleteIssueComment(w http.ResponseWriter, r *http.Request) {
// delete from pds
if comment.Rkey != "" {
- client, _ := s.auth.AuthorizedClient(r)
- _, err = comatproto.RepoDeleteRecord(r.Context(), client, &comatproto.RepoDeleteRecord_Input{
+ client, err := s.oauth.AuthorizedClient(r)
+ if err != nil {
+ log.Println("failed to get authorized client", err)
+ s.pages.Notice(w, "issue-comment", "Failed to delete comment.")
+ return
+ }
+ _, err = client.RepoDeleteRecord(r.Context(), &comatproto.RepoDeleteRecord_Input{
Collection: tangled.GraphFollowNSID,
Repo: user.Did,
Rkey: comment.Rkey,
@@ -1647,7 +1675,7 @@ func (s *State) RepoIssues(w http.ResponseWriter, r *http.Request) {
page = pagination.FirstPage()
}
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
f, err := s.fullyResolvedRepo(r)
if err != nil {
log.Println("failed to get repo and knot", err)
@@ -1676,7 +1704,7 @@ func (s *State) RepoIssues(w http.ResponseWriter, r *http.Request) {
}
s.pages.RepoIssues(w, pages.RepoIssuesParams{
- LoggedInUser: s.auth.GetUser(r),
+ LoggedInUser: s.oauth.GetUser(r),
RepoInfo: f.RepoInfo(s, user),
Issues: issues,
DidHandleMap: didHandleMap,
@@ -1687,7 +1715,7 @@ func (s *State) RepoIssues(w http.ResponseWriter, r *http.Request) {
}
func (s *State) NewIssue(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
f, err := s.fullyResolvedRepo(r)
if err != nil {
@@ -1735,9 +1763,14 @@ func (s *State) NewIssue(w http.ResponseWriter, r *http.Request) {
return
}
- client, _ := s.auth.AuthorizedClient(r)
+ client, err := s.oauth.AuthorizedClient(r)
+ if err != nil {
+ log.Println("failed to get authorized client", err)
+ s.pages.Notice(w, "issues", "Failed to create issue.")
+ return
+ }
atUri := f.RepoAt.String()
- resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
+ resp, err := client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
Collection: tangled.RepoIssueNSID,
Repo: user.Did,
Rkey: appview.TID(),
@@ -1770,7 +1803,7 @@ func (s *State) NewIssue(w http.ResponseWriter, r *http.Request) {
}
func (s *State) ForkRepo(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
f, err := s.fullyResolvedRepo(r)
if err != nil {
log.Printf("failed to resolve source repo: %v", err)
@@ -1779,7 +1812,7 @@ func (s *State) ForkRepo(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
knots, err := s.enforcer.GetDomainsForUser(user.Did)
if err != nil {
s.pages.Notice(w, "repo", "Invalid user account.")
@@ -1829,14 +1862,14 @@ func (s *State) ForkRepo(w http.ResponseWriter, r *http.Request) {
return
}
- client, err := NewSignedClient(knot, secret, s.config.Dev)
+ client, err := NewSignedClient(knot, secret, s.config.Core.Dev)
if err != nil {
s.pages.Notice(w, "repo", "Failed to reach knot server.")
return
}
var uri string
- if s.config.Dev {
+ if s.config.Core.Dev {
uri = "http"
} else {
uri = "https"
@@ -1883,10 +1916,15 @@ func (s *State) ForkRepo(w http.ResponseWriter, r *http.Request) {
// continue
}
- xrpcClient, _ := s.auth.AuthorizedClient(r)
+ xrpcClient, err := s.oauth.AuthorizedClient(r)
+ if err != nil {
+ log.Println("failed to get authorized client", err)
+ s.pages.Notice(w, "repo", "Failed to create repository.")
+ return
+ }
createdAt := time.Now().Format(time.RFC3339)
- atresp, err := comatproto.RepoPutRecord(r.Context(), xrpcClient, &comatproto.RepoPutRecord_Input{
+ atresp, err := xrpcClient.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
Collection: tangled.RepoNSID,
Repo: user.Did,
Rkey: rkey,
diff --git a/appview/state/repo_util.go b/appview/state/repo_util.go
index 9ca3b2de..df8d8679 100644
--- a/appview/state/repo_util.go
+++ b/appview/state/repo_util.go
@@ -12,8 +12,8 @@ import (
"github.com/bluesky-social/indigo/atproto/syntax"
"github.com/go-chi/chi/v5"
"github.com/go-git/go-git/v5/plumbing/object"
- "tangled.sh/tangled.sh/core/appview/auth"
"tangled.sh/tangled.sh/core/appview/db"
+ "tangled.sh/tangled.sh/core/appview/oauth"
"tangled.sh/tangled.sh/core/appview/pages/repoinfo"
)
@@ -45,7 +45,7 @@ func (s *State) fullyResolvedRepo(r *http.Request) (*FullyResolvedRepo, error) {
ref := chi.URLParam(r, "ref")
if ref == "" {
- us, err := NewUnsignedClient(knot, s.config.Dev)
+ us, err := NewUnsignedClient(knot, s.config.Core.Dev)
if err != nil {
return nil, err
}
@@ -73,7 +73,7 @@ func (s *State) fullyResolvedRepo(r *http.Request) (*FullyResolvedRepo, error) {
}, nil
}
-func RolesInRepo(s *State, u *auth.User, f *FullyResolvedRepo) repoinfo.RolesInRepo {
+func RolesInRepo(s *State, u *oauth.User, f *FullyResolvedRepo) repoinfo.RolesInRepo {
if u != nil {
r := s.enforcer.GetPermissionsInRepo(u.Did, f.Knot, f.DidSlashRepo())
return repoinfo.RolesInRepo{r}
diff --git a/appview/state/router.go b/appview/state/router.go
index 788ea62b..44605b4b 100644
--- a/appview/state/router.go
+++ b/appview/state/router.go
@@ -5,7 +5,9 @@ import (
"strings"
"github.com/go-chi/chi/v5"
+ "github.com/gorilla/sessions"
"tangled.sh/tangled.sh/core/appview/middleware"
+ oauthhandler "tangled.sh/tangled.sh/core/appview/oauth/handler"
"tangled.sh/tangled.sh/core/appview/settings"
"tangled.sh/tangled.sh/core/appview/state/userutil"
)
@@ -67,7 +69,7 @@ func (s *State) UserRouter() http.Handler {
r.Route("/tags", func(r chi.Router) {
r.Get("/", s.RepoTags)
r.Route("/{tag}", func(r chi.Router) {
- r.Use(middleware.AuthMiddleware(s.auth))
+ r.Use(middleware.AuthMiddleware(s.oauth))
// require auth to download for now
r.Get("/download/{file}", s.DownloadArtifact)
@@ -90,7 +92,7 @@ func (s *State) UserRouter() http.Handler {
r.Get("/{issue}", s.RepoSingleIssue)
r.Group(func(r chi.Router) {
- r.Use(middleware.AuthMiddleware(s.auth))
+ r.Use(middleware.AuthMiddleware(s.oauth))
r.Get("/new", s.NewIssue)
r.Post("/new", s.NewIssue)
r.Post("/{issue}/comment", s.NewIssueComment)
@@ -106,14 +108,14 @@ func (s *State) UserRouter() http.Handler {
})
r.Route("/fork", func(r chi.Router) {
- r.Use(middleware.AuthMiddleware(s.auth))
+ r.Use(middleware.AuthMiddleware(s.oauth))
r.Get("/", s.ForkRepo)
r.Post("/", s.ForkRepo)
})
r.Route("/pulls", func(r chi.Router) {
r.Get("/", s.RepoPulls)
- r.With(middleware.AuthMiddleware(s.auth)).Route("/new", func(r chi.Router) {
+ r.With(middleware.AuthMiddleware(s.oauth)).Route("/new", func(r chi.Router) {
r.Get("/", s.NewPull)
r.Get("/patch-upload", s.PatchUploadFragment)
r.Post("/validate-patch", s.ValidatePatch)
@@ -131,7 +133,7 @@ func (s *State) UserRouter() http.Handler {
r.Get("/", s.RepoPullPatch)
r.Get("/interdiff", s.RepoPullInterdiff)
r.Get("/actions", s.PullActions)
- r.With(middleware.AuthMiddleware(s.auth)).Route("/comment", func(r chi.Router) {
+ r.With(middleware.AuthMiddleware(s.oauth)).Route("/comment", func(r chi.Router) {
r.Get("/", s.PullComment)
r.Post("/", s.PullComment)
})
@@ -142,7 +144,7 @@ func (s *State) UserRouter() http.Handler {
})
r.Group(func(r chi.Router) {
- r.Use(middleware.AuthMiddleware(s.auth))
+ r.Use(middleware.AuthMiddleware(s.oauth))
r.Route("/resubmit", func(r chi.Router) {
r.Get("/", s.ResubmitPull)
r.Post("/", s.ResubmitPull)
@@ -165,7 +167,7 @@ func (s *State) UserRouter() http.Handler {
// settings routes, needs auth
r.Group(func(r chi.Router) {
- r.Use(middleware.AuthMiddleware(s.auth))
+ r.Use(middleware.AuthMiddleware(s.oauth))
// repo description can only be edited by owner
r.With(RepoPermissionMiddleware(s, "repo:owner")).Route("/description", func(r chi.Router) {
r.Put("/", s.RepoDescription)
@@ -196,15 +198,15 @@ func (s *State) StandardRouter() http.Handler {
r.Get("/", s.Timeline)
- r.With(middleware.AuthMiddleware(s.auth)).Post("/logout", s.Logout)
+ r.With(middleware.AuthMiddleware(s.oauth)).Post("/logout", s.Logout)
- r.Route("/login", func(r chi.Router) {
- r.Get("/", s.Login)
- r.Post("/", s.Login)
- })
+ // r.Route("/login", func(r chi.Router) {
+ // r.Get("/", s.Login)
+ // r.Post("/", s.Login)
+ // })
r.Route("/knots", func(r chi.Router) {
- r.Use(middleware.AuthMiddleware(s.auth))
+ r.Use(middleware.AuthMiddleware(s.oauth))
r.Get("/", s.Knots)
r.Post("/key", s.RegistrationKey)
@@ -222,25 +224,25 @@ func (s *State) StandardRouter() http.Handler {
r.Route("/repo", func(r chi.Router) {
r.Route("/new", func(r chi.Router) {
- r.Use(middleware.AuthMiddleware(s.auth))
+ r.Use(middleware.AuthMiddleware(s.oauth))
r.Get("/", s.NewRepo)
r.Post("/", s.NewRepo)
})
// r.Post("/import", s.ImportRepo)
})
- r.With(middleware.AuthMiddleware(s.auth)).Route("/follow", func(r chi.Router) {
+ r.With(middleware.AuthMiddleware(s.oauth)).Route("/follow", func(r chi.Router) {
r.Post("/", s.Follow)
r.Delete("/", s.Follow)
})
- r.With(middleware.AuthMiddleware(s.auth)).Route("/star", func(r chi.Router) {
+ r.With(middleware.AuthMiddleware(s.oauth)).Route("/star", func(r chi.Router) {
r.Post("/", s.Star)
r.Delete("/", s.Star)
})
r.Route("/profile", func(r chi.Router) {
- r.Use(middleware.AuthMiddleware(s.auth))
+ r.Use(middleware.AuthMiddleware(s.oauth))
r.Get("/edit-bio", s.EditBioFragment)
r.Get("/edit-pins", s.EditPinsFragment)
r.Post("/bio", s.UpdateProfileBio)
@@ -248,7 +250,7 @@ func (s *State) StandardRouter() http.Handler {
})
r.Mount("/settings", s.SettingsRouter())
-
+ r.Mount("/oauth", s.OAuthRouter())
r.Get("/keys/{user}", s.Keys)
r.NotFound(func(w http.ResponseWriter, r *http.Request) {
@@ -257,10 +259,23 @@ func (s *State) StandardRouter() http.Handler {
return r
}
+func (s *State) OAuthRouter() http.Handler {
+ oauth := &oauthhandler.OAuthHandler{
+ Config: s.config,
+ Pages: s.pages,
+ Resolver: s.resolver,
+ Db: s.db,
+ Store: sessions.NewCookieStore([]byte(s.config.Core.CookieSecret)),
+ OAuth: s.oauth,
+ }
+
+ return oauth.Router()
+}
+
func (s *State) SettingsRouter() http.Handler {
settings := &settings.Settings{
Db: s.db,
- Auth: s.auth,
+ OAuth: s.oauth,
Pages: s.pages,
Config: s.config,
}
diff --git a/appview/state/star.go b/appview/state/star.go
index 08969f2d..7f4635fa 100644
--- a/appview/state/star.go
+++ b/appview/state/star.go
@@ -15,7 +15,7 @@ import (
)
func (s *State) Star(w http.ResponseWriter, r *http.Request) {
- currentUser := s.auth.GetUser(r)
+ currentUser := s.oauth.GetUser(r)
subject := r.URL.Query().Get("subject")
if subject == "" {
@@ -29,13 +29,17 @@ func (s *State) Star(w http.ResponseWriter, r *http.Request) {
return
}
- client, _ := s.auth.AuthorizedClient(r)
+ client, err := s.oauth.AuthorizedClient(r)
+ if err != nil {
+ log.Println("failed to authorize client", err)
+ return
+ }
switch r.Method {
case http.MethodPost:
createdAt := time.Now().Format(time.RFC3339)
rkey := appview.TID()
- resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
+ resp, err := client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
Collection: tangled.FeedStarNSID,
Repo: currentUser.Did,
Rkey: rkey,
@@ -80,7 +84,7 @@ func (s *State) Star(w http.ResponseWriter, r *http.Request) {
return
}
- _, err = comatproto.RepoDeleteRecord(r.Context(), client, &comatproto.RepoDeleteRecord_Input{
+ _, err = client.RepoDeleteRecord(r.Context(), &comatproto.RepoDeleteRecord_Input{
Collection: tangled.FeedStarNSID,
Repo: currentUser.Did,
Rkey: star.Rkey,
diff --git a/appview/state/state.go b/appview/state/state.go
index 7f901f48..7bb64d7d 100644
--- a/appview/state/state.go
+++ b/appview/state/state.go
@@ -21,6 +21,7 @@ import (
"tangled.sh/tangled.sh/core/appview"
"tangled.sh/tangled.sh/core/appview/auth"
"tangled.sh/tangled.sh/core/appview/db"
+ "tangled.sh/tangled.sh/core/appview/oauth"
"tangled.sh/tangled.sh/core/appview/pages"
"tangled.sh/tangled.sh/core/jetstream"
"tangled.sh/tangled.sh/core/rbac"
@@ -29,8 +30,9 @@ import (
type State struct {
db *db.DB
auth *auth.Auth
+ oauth *oauth.OAuth
enforcer *rbac.Enforcer
- tidClock *syntax.TIDClock
+ tidClock syntax.TIDClock
pages *pages.Pages
resolver *appview.Resolver
jc *jetstream.JetstreamClient
@@ -38,17 +40,17 @@ type State struct {
}
func Make(config *appview.Config) (*State, error) {
- d, err := db.Make(config.DbPath)
+ d, err := db.Make(config.Core.DbPath)
if err != nil {
return nil, err
}
- auth, err := auth.Make(config.CookieSecret)
+ auth, err := auth.Make(config.Core.CookieSecret)
if err != nil {
return nil, err
}
- enforcer, err := rbac.NewEnforcer(config.DbPath)
+ enforcer, err := rbac.NewEnforcer(config.Core.DbPath)
if err != nil {
return nil, err
}
@@ -59,9 +61,11 @@ func Make(config *appview.Config) (*State, error) {
resolver := appview.NewResolver()
+ oauth := oauth.NewOAuth(d, config)
+
wrapper := db.DbWrapper{d}
jc, err := jetstream.NewJetstreamClient(
- config.JetstreamEndpoint,
+ config.Jetstream.Endpoint,
"appview",
[]string{
tangled.GraphFollowNSID,
@@ -86,6 +90,7 @@ func Make(config *appview.Config) (*State, error) {
state := &State{
d,
auth,
+ oauth,
enforcer,
clock,
pgs,
@@ -101,90 +106,90 @@ func TID(c *syntax.TIDClock) string {
return c.Next().String()
}
-func (s *State) Login(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
-
- switch r.Method {
- case http.MethodGet:
- err := s.pages.Login(w, pages.LoginParams{})
- if err != nil {
- log.Printf("rendering login page: %s", err)
- }
-
- return
- case http.MethodPost:
- handle := strings.TrimPrefix(r.FormValue("handle"), "@")
- appPassword := r.FormValue("app_password")
-
- resolved, err := s.resolver.ResolveIdent(ctx, handle)
- if err != nil {
- log.Println("failed to resolve handle:", err)
- s.pages.Notice(w, "login-msg", fmt.Sprintf("\"%s\" is an invalid handle.", handle))
- return
- }
-
- atSession, err := s.auth.CreateInitialSession(ctx, resolved, appPassword)
- if err != nil {
- s.pages.Notice(w, "login-msg", "Invalid handle or password.")
- return
- }
- sessionish := auth.CreateSessionWrapper{ServerCreateSession_Output: atSession}
-
- err = s.auth.StoreSession(r, w, &sessionish, resolved.PDSEndpoint())
- if err != nil {
- s.pages.Notice(w, "login-msg", "Failed to login, try again later.")
- return
- }
-
- log.Printf("successfully saved session for %s (%s)", atSession.Handle, atSession.Did)
-
- did := resolved.DID.String()
- defaultKnot := "knot1.tangled.sh"
-
- go func() {
- log.Printf("adding %s to default knot", did)
- err = s.enforcer.AddMember(defaultKnot, did)
- if err != nil {
- log.Println("failed to add user to knot1.tangled.sh: ", err)
- return
- }
- err = s.enforcer.E.SavePolicy()
- if err != nil {
- log.Println("failed to add user to knot1.tangled.sh: ", err)
- return
- }
-
- secret, err := db.GetRegistrationKey(s.db, defaultKnot)
- if err != nil {
- log.Println("failed to get registration key for knot1.tangled.sh")
- return
- }
- signedClient, err := NewSignedClient(defaultKnot, secret, s.config.Dev)
- resp, err := signedClient.AddMember(did)
- if err != nil {
- log.Println("failed to add user to knot1.tangled.sh: ", err)
- return
- }
-
- if resp.StatusCode != http.StatusNoContent {
- log.Println("failed to add user to knot1.tangled.sh: ", resp.StatusCode)
- return
- }
- }()
-
- s.pages.HxRedirect(w, "/")
- return
- }
-}
+// func (s *State) Login(w http.ResponseWriter, r *http.Request) {
+// ctx := r.Context()
+
+// switch r.Method {
+// case http.MethodGet:
+// err := s.pages.Login(w, pages.LoginParams{})
+// if err != nil {
+// log.Printf("rendering login page: %s", err)
+// }
+
+// return
+// case http.MethodPost:
+// handle := strings.TrimPrefix(r.FormValue("handle"), "@")
+// appPassword := r.FormValue("app_password")
+
+// resolved, err := s.resolver.ResolveIdent(ctx, handle)
+// if err != nil {
+// log.Println("failed to resolve handle:", err)
+// s.pages.Notice(w, "login-msg", fmt.Sprintf("\"%s\" is an invalid handle.", handle))
+// return
+// }
+
+// atSession, err := s.oauth.CreateInitialSession(ctx, resolved, appPassword)
+// if err != nil {
+// s.pages.Notice(w, "login-msg", "Invalid handle or password.")
+// return
+// }
+// sessionish := auth.CreateSessionWrapper{ServerCreateSession_Output: atSession}
+
+// err = s.oauth.StoreSession(r, w, &sessionish, resolved.PDSEndpoint())
+// if err != nil {
+// s.pages.Notice(w, "login-msg", "Failed to login, try again later.")
+// return
+// }
+
+// log.Printf("successfully saved session for %s (%s)", atSession.Handle, atSession.Did)
+
+// did := resolved.DID.String()
+// defaultKnot := "knot1.tangled.sh"
+
+// go func() {
+// log.Printf("adding %s to default knot", did)
+// err = s.enforcer.AddMember(defaultKnot, did)
+// if err != nil {
+// log.Println("failed to add user to knot1.tangled.sh: ", err)
+// return
+// }
+// err = s.enforcer.E.SavePolicy()
+// if err != nil {
+// log.Println("failed to add user to knot1.tangled.sh: ", err)
+// return
+// }
+
+// secret, err := db.GetRegistrationKey(s.db, defaultKnot)
+// if err != nil {
+// log.Println("failed to get registration key for knot1.tangled.sh")
+// return
+// }
+// signedClient, err := NewSignedClient(defaultKnot, secret, s.config.Core.Dev)
+// resp, err := signedClient.AddMember(did)
+// if err != nil {
+// log.Println("failed to add user to knot1.tangled.sh: ", err)
+// return
+// }
+
+// if resp.StatusCode != http.StatusNoContent {
+// log.Println("failed to add user to knot1.tangled.sh: ", resp.StatusCode)
+// return
+// }
+// }()
+
+// s.pages.HxRedirect(w, "/")
+// return
+// }
+// }
func (s *State) Logout(w http.ResponseWriter, r *http.Request) {
- s.auth.ClearSession(r, w)
+ s.oauth.ClearSession(r, w)
w.Header().Set("HX-Redirect", "/login")
w.WriteHeader(http.StatusSeeOther)
}
func (s *State) Timeline(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
timeline, err := db.MakeTimeline(s.db)
if err != nil {
@@ -235,7 +240,7 @@ func (s *State) RegistrationKey(w http.ResponseWriter, r *http.Request) {
return
case http.MethodPost:
- session, err := s.auth.Store.Get(r, appview.SessionName)
+ session, err := s.oauth.Store.Get(r, appview.SessionName)
if err != nil || session.IsNew {
log.Println("unauthorized attempt to generate registration key")
http.Error(w, "Forbidden", http.StatusUnauthorized)
@@ -297,7 +302,7 @@ func (s *State) Keys(w http.ResponseWriter, r *http.Request) {
// create a signed request and check if a node responds to that
func (s *State) InitKnotServer(w http.ResponseWriter, r *http.Request) {
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
domain := chi.URLParam(r, "domain")
if domain == "" {
@@ -312,7 +317,7 @@ func (s *State) InitKnotServer(w http.ResponseWriter, r *http.Request) {
return
}
- client, err := NewSignedClient(domain, secret, s.config.Dev)
+ client, err := NewSignedClient(domain, secret, s.config.Core.Dev)
if err != nil {
log.Println("failed to create client to ", domain)
}
@@ -421,7 +426,7 @@ func (s *State) KnotServerInfo(w http.ResponseWriter, r *http.Request) {
return
}
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
reg, err := db.RegistrationByDomain(s.db, domain)
if err != nil {
w.Write([]byte("failed to pull up registration info"))
@@ -469,7 +474,7 @@ func (s *State) KnotServerInfo(w http.ResponseWriter, r *http.Request) {
// get knots registered by this user
func (s *State) Knots(w http.ResponseWriter, r *http.Request) {
// for now, this is just pubkeys
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
registrations, err := db.RegistrationsByDid(s.db, user.Did)
if err != nil {
log.Println(err)
@@ -522,10 +527,14 @@ func (s *State) AddMember(w http.ResponseWriter, r *http.Request) {
log.Printf("adding %s to %s\n", subjectIdentity.Handle.String(), domain)
// announce this relation into the firehose, store into owners' pds
- client, _ := s.auth.AuthorizedClient(r)
- currentUser := s.auth.GetUser(r)
+ client, err := s.oauth.AuthorizedClient(r)
+ if err != nil {
+ http.Error(w, "failed to authorize client", http.StatusInternalServerError)
+ return
+ }
+ currentUser := s.oauth.GetUser(r)
createdAt := time.Now().Format(time.RFC3339)
- resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
+ resp, err := client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
Collection: tangled.KnotMemberNSID,
Repo: currentUser.Did,
Rkey: appview.TID(),
@@ -550,7 +559,7 @@ func (s *State) AddMember(w http.ResponseWriter, r *http.Request) {
return
}
- ksClient, err := NewSignedClient(domain, secret, s.config.Dev)
+ ksClient, err := NewSignedClient(domain, secret, s.config.Core.Dev)
if err != nil {
log.Println("failed to create client to ", domain)
return
@@ -614,7 +623,7 @@ func validateRepoName(name string) error {
func (s *State) NewRepo(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodGet:
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
knots, err := s.enforcer.GetDomainsForUser(user.Did)
if err != nil {
s.pages.Notice(w, "repo", "Invalid user account.")
@@ -627,7 +636,7 @@ func (s *State) NewRepo(w http.ResponseWriter, r *http.Request) {
})
case http.MethodPost:
- user := s.auth.GetUser(r)
+ user := s.oauth.GetUser(r)
domain := r.FormValue("domain")
if domain == "" {
@@ -671,7 +680,7 @@ func (s *State) NewRepo(w http.ResponseWriter, r *http.Request) {
return
}
- client, err := NewSignedClient(domain, secret, s.config.Dev)
+ client, err := NewSignedClient(domain, secret, s.config.Core.Dev)
if err != nil {
s.pages.Notice(w, "repo", "Failed to connect to knot server.")
return
@@ -686,10 +695,14 @@ func (s *State) NewRepo(w http.ResponseWriter, r *http.Request) {
Description: description,
}
- xrpcClient, _ := s.auth.AuthorizedClient(r)
+ xrpcClient, err := s.oauth.AuthorizedClient(r)
+ if err != nil {
+ s.pages.Notice(w, "repo", "Failed to write record to PDS.")
+ return
+ }
createdAt := time.Now().Format(time.RFC3339)
- atresp, err := comatproto.RepoPutRecord(r.Context(), xrpcClient, &comatproto.RepoPutRecord_Input{
+ atresp, err := xrpcClient.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
Collection: tangled.RepoNSID,
Repo: user.Did,
Rkey: rkey,
diff --git a/appview/tid.go b/appview/tid.go
index 46a4da67..7d0f0269 100644
--- a/appview/tid.go
+++ b/appview/tid.go
@@ -4,7 +4,7 @@ import (
"github.com/bluesky-social/indigo/atproto/syntax"
)
-var c *syntax.TIDClock = syntax.NewTIDClock(0)
+var c syntax.TIDClock = syntax.NewTIDClock(0)
func TID() string {
return c.Next().String()
diff --git a/cmd/appview/main.go b/cmd/appview/main.go
index 2cc33c24..98b7a556 100644
--- a/cmd/appview/main.go
+++ b/cmd/appview/main.go
@@ -26,6 +26,6 @@ func main() {
log.Fatal(err)
}
- log.Println("starting server on", c.ListenAddr)
- log.Println(http.ListenAndServe(c.ListenAddr, state.Router()))
+ log.Println("starting server on", c.Core.ListenAddr)
+ log.Println(http.ListenAndServe(c.Core.ListenAddr, state.Router()))
}