diff --git a/account.go b/account.go index fbe5ad0..236dfb3 100644 --- a/account.go +++ b/account.go @@ -304,32 +304,18 @@ func viewLogin(app *App, w http.ResponseWriter, r *http.Request) error { p := &struct { page.StaticPage - To string - Message template.HTML - Flashes []template.HTML - LoginUsername string - OauthSlack bool - OauthWriteAs bool - OauthGitlab bool - GitlabDisplayName string - OauthGeneric bool - OauthGenericDisplayName string - OauthGitea bool - GiteaDisplayName string + *OAuthButtons + To string + Message template.HTML + Flashes []template.HTML + LoginUsername string }{ - pageForReq(app, r), - r.FormValue("to"), - template.HTML(""), - []template.HTML{}, - getTempInfo(app, "login-user", r, w), - app.Config().SlackOauth.ClientID != "", - app.Config().WriteAsOauth.ClientID != "", - app.Config().GitlabOauth.ClientID != "", - config.OrDefaultString(app.Config().GenericOauth.DisplayName, genericOauthDisplayName), - app.Config().GenericOauth.ClientID != "", - config.OrDefaultString(app.Config().GitlabOauth.DisplayName, gitlabDisplayName), - app.Config().GiteaOauth.ClientID != "", - config.OrDefaultString(app.Config().GiteaOauth.DisplayName, giteaDisplayName), + StaticPage: pageForReq(app, r), + OAuthButtons: NewOAuthButtons(app.Config()), + To: r.FormValue("to"), + Message: template.HTML(""), + Flashes: []template.HTML{}, + LoginUsername: getTempInfo(app, "login-user", r, w), } if earlyError != "" { diff --git a/activitypub.go b/activitypub.go index d34e70c..0e69075 100644 --- a/activitypub.go +++ b/activitypub.go @@ -494,7 +494,7 @@ func makeActivityPost(hostName string, p *activitystreams.Person, url string, m r, _ := http.NewRequest("POST", url, bytes.NewBuffer(b)) r.Header.Add("Content-Type", "application/activity+json") - r.Header.Set("User-Agent", "Go ("+serverSoftware+"/"+softwareVer+"; +"+hostName+")") + r.Header.Set("User-Agent", ServerUserAgent(hostName)) h := sha256.New() h.Write(b) r.Header.Add("Digest", "SHA-256="+base64.StdEncoding.EncodeToString(h.Sum(nil))) @@ -544,7 +544,7 @@ func resolveIRI(hostName, url string) ([]byte, error) { r, _ := http.NewRequest("GET", url, nil) r.Header.Add("Accept", "application/activity+json") - r.Header.Set("User-Agent", "Go ("+serverSoftware+"/"+softwareVer+"; +"+hostName+")") + r.Header.Set("User-Agent", ServerUserAgent(hostName)) if debugging { dump, err := httputil.DumpRequestOut(r, true) diff --git a/app.go b/app.go index af0a56f..2aed437 100644 --- a/app.go +++ b/app.go @@ -238,27 +238,16 @@ func handleViewLanding(app *App, w http.ResponseWriter, r *http.Request) error { p := struct { page.StaticPage + *OAuthButtons Flashes []template.HTML Banner template.HTML Content template.HTML ForcedLanding bool - - OauthSlack bool - OauthWriteAs bool - OauthGitlab bool - OauthGeneric bool - OauthGenericDisplayName string - GitlabDisplayName string }{ - StaticPage: pageForReq(app, r), - ForcedLanding: forceLanding, - OauthSlack: app.Config().SlackOauth.ClientID != "", - OauthWriteAs: app.Config().WriteAsOauth.ClientID != "", - OauthGitlab: app.Config().GitlabOauth.ClientID != "", - OauthGeneric: app.Config().GenericOauth.ClientID != "", - OauthGenericDisplayName: config.OrDefaultString(app.Config().GenericOauth.DisplayName, genericOauthDisplayName), - GitlabDisplayName: config.OrDefaultString(app.Config().GitlabOauth.DisplayName, gitlabDisplayName), + StaticPage: pageForReq(app, r), + OAuthButtons: NewOAuthButtons(app.Config()), + ForcedLanding: forceLanding, } banner, err := getLandingBanner(app) @@ -903,3 +892,13 @@ func adminInitDatabase(app *App) error { log.Info("Done.") return nil } + +// ServerUserAgent returns a User-Agent string to use in external requests. The +// hostName parameter may be left empty. +func ServerUserAgent(hostName string) string { + hostUAStr := "" + if hostName != "" { + hostUAStr = "; +" + hostName + } + return "Go (" + serverSoftware + "/" + softwareVer + hostUAStr + ")" +} diff --git a/config/config.go b/config/config.go index 9ff13f8..7b64e02 100644 --- a/config/config.go +++ b/config/config.go @@ -81,6 +81,15 @@ type ( CallbackProxyAPI string `ini:"callback_proxy_api"` } + GiteaOauthCfg struct { + ClientID string `ini:"client_id"` + ClientSecret string `ini:"client_secret"` + Host string `ini:"host"` + DisplayName string `ini:"display_name"` + CallbackProxy string `ini:"callback_proxy"` + CallbackProxyAPI string `ini:"callback_proxy_api"` + } + SlackOauthCfg struct { ClientID string `ini:"client_id"` ClientSecret string `ini:"client_secret"` @@ -101,14 +110,6 @@ type ( AuthEndpoint string `ini:"auth_endpoint"` AllowDisconnect bool `ini:"allow_disconnect"` } - GiteaOauthCfg struct { - ClientID string `ini:"client_id"` - ClientSecret string `ini:"client_secret"` - Host string `ini:"host"` - DisplayName string `ini:"display_name"` - CallbackProxy string `ini:"callback_proxy"` - CallbackProxyAPI string `ini:"callback_proxy_api"` - } // AppCfg holds values that affect how the application functions AppCfg struct { @@ -165,8 +166,8 @@ type ( SlackOauth SlackOauthCfg `ini:"oauth.slack"` WriteAsOauth WriteAsOauthCfg `ini:"oauth.writeas"` GitlabOauth GitlabOauthCfg `ini:"oauth.gitlab"` - GenericOauth GenericOauthCfg `ini:"oauth.generic"` GiteaOauth GiteaOauthCfg `ini:"oauth.gitea"` + GenericOauth GenericOauthCfg `ini:"oauth.generic"` } ) diff --git a/database.go b/database.go index c764340..8237e41 100644 --- a/database.go +++ b/database.go @@ -2627,11 +2627,11 @@ func (db *datastore) GetIDForRemoteUser(ctx context.Context, remoteUserID, provi } type oauthAccountInfo struct { - Provider string - ClientID string - RemoteUserID string - DisplayName string - AllowDisconnect bool + Provider string + ClientID string + RemoteUserID string + DisplayName string + AllowDisconnect bool } func (db *datastore) GetOauthAccounts(ctx context.Context, userID int64) ([]oauthAccountInfo, error) { diff --git a/invites.go b/invites.go index 10416b2..4e3eff4 100644 --- a/invites.go +++ b/invites.go @@ -170,14 +170,14 @@ func handleViewInvite(app *App, w http.ResponseWriter, r *http.Request) error { p := struct { page.StaticPage + *OAuthButtons Error string Flashes []template.HTML Invite string - OAuth *OAuthButtons }{ - StaticPage: pageForReq(app, r), - Invite: inviteCode, - OAuth: NewOAuthButtons(app.cfg), + StaticPage: pageForReq(app, r), + OAuthButtons: NewOAuthButtons(app.cfg), + Invite: inviteCode, } if expired { diff --git a/less/login.less b/less/login.less index 473d26f..fefeb12 100644 --- a/less/login.less +++ b/less/login.less @@ -9,18 +9,64 @@ */ .row.signinbtns { - justify-content: space-evenly; + justify-content: center; font-size: 1em; margin-top: 2em; margin-bottom: 1em; + flex-wrap: wrap; .loginbtn { height: 40px; - } + margin: 0.5em; + + &.btn { + box-sizing: border-box; + font-size: 17px; + white-space: nowrap; + + img { + height: 1.5em; + vertical-align: middle; + } + } + + writeas-login, slack-login { + img { + margin-top: -0.2em; + } + } + + gitlab-login { + background-color: #fc6d26; + border-color: #fc6d26; + &:hover { + background-color: darken(#fc6d26, 5%); + border-color: darken(#fc6d26, 5%); + } + } + + gitea-login { + background-color: #2ecc71; + border-color: #2ecc71; + &:hover { + background-color: #2cc26b; + border-color: #2cc26b; + } + } + + slack-login, gitlab-login, gitea-login, generic-oauth-login { + font-size: 0.86em; + font-family: @sansFont; + } - #writeas-login, #gitlab-login { - box-sizing: border-box; - font-size: 17px; + slack-login, generic-oauth-login { + color: @lightTextColor; + background-color: @lightNavBG; + border-color: @lightNavBorder; + &:hover { + background-color: @lightNavHoverBG; + } + } } } diff --git a/oauth.go b/oauth.go index fe9fe74..e3f65ef 100644 --- a/oauth.go +++ b/oauth.go @@ -30,19 +30,27 @@ import ( // OAuthButtons holds display information for different OAuth providers we support. type OAuthButtons struct { - SlackEnabled bool - WriteAsEnabled bool - GitLabEnabled bool - GitLabDisplayName string + SlackEnabled bool + WriteAsEnabled bool + GitLabEnabled bool + GitLabDisplayName string + GiteaEnabled bool + GiteaDisplayName string + GenericEnabled bool + GenericDisplayName string } // NewOAuthButtons creates a new OAuthButtons struct based on our app configuration. func NewOAuthButtons(cfg *config.Config) *OAuthButtons { return &OAuthButtons{ - SlackEnabled: cfg.SlackOauth.ClientID != "", - WriteAsEnabled: cfg.WriteAsOauth.ClientID != "", - GitLabEnabled: cfg.GitlabOauth.ClientID != "", - GitLabDisplayName: config.OrDefaultString(cfg.GitlabOauth.DisplayName, gitlabDisplayName), + SlackEnabled: cfg.SlackOauth.ClientID != "", + WriteAsEnabled: cfg.WriteAsOauth.ClientID != "", + GitLabEnabled: cfg.GitlabOauth.ClientID != "", + GitLabDisplayName: config.OrDefaultString(cfg.GitlabOauth.DisplayName, gitlabDisplayName), + GiteaEnabled: cfg.GiteaOauth.ClientID != "", + GiteaDisplayName: config.OrDefaultString(cfg.GiteaOauth.DisplayName, giteaDisplayName), + GenericEnabled: cfg.GenericOauth.ClientID != "", + GenericDisplayName: config.OrDefaultString(cfg.GenericOauth.DisplayName, genericOauthDisplayName), } } @@ -318,6 +326,12 @@ func (h oauthHandler) viewOauthCallback(app *App, w http.ResponseWriter, r *http tokenResponse, err := h.oauthClient.exchangeOauthCode(ctx, code) if err != nil { log.Error("Unable to exchangeOauthCode: %s", err) + // TODO: show user friendly message if needed + // TODO: show NO message for cases like user pressing "Cancel" on authorize step + addSessionFlash(app, w, r, err.Error(), nil) + if attachUserID > 0 { + return impart.HTTPError{http.StatusFound, "/me/settings"} + } return impart.HTTPError{http.StatusInternalServerError, err.Error()} } @@ -408,7 +422,7 @@ func (r *callbackProxyClient) register(ctx context.Context, state string) error if err != nil { return err } - req.Header.Set("User-Agent", "writefreely") + req.Header.Set("User-Agent", ServerUserAgent("")) req.Header.Set("Accept", "application/json") req.Header.Set("Content-Type", "application/x-www-form-urlencoded") diff --git a/oauth_generic.go b/oauth_generic.go index 42c84b0..ce65bca 100644 --- a/oauth_generic.go +++ b/oauth_generic.go @@ -62,7 +62,7 @@ func (c genericOauthClient) exchangeOauthCode(ctx context.Context, code string) return nil, err } req.WithContext(ctx) - req.Header.Set("User-Agent", "writefreely") + req.Header.Set("User-Agent", ServerUserAgent("")) req.Header.Set("Accept", "application/json") req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.SetBasicAuth(c.ClientID, c.ClientSecret) @@ -91,7 +91,7 @@ func (c genericOauthClient) inspectOauthAccessToken(ctx context.Context, accessT return nil, err } req.WithContext(ctx) - req.Header.Set("User-Agent", "writefreely") + req.Header.Set("User-Agent", ServerUserAgent("")) req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", "Bearer "+accessToken) diff --git a/oauth_gitea.go b/oauth_gitea.go index e6e1000..a9b7741 100644 --- a/oauth_gitea.go +++ b/oauth_gitea.go @@ -62,7 +62,7 @@ func (c giteaOauthClient) exchangeOauthCode(ctx context.Context, code string) (* return nil, err } req.WithContext(ctx) - req.Header.Set("User-Agent", "writefreely") + req.Header.Set("User-Agent", ServerUserAgent("")) req.Header.Set("Accept", "application/json") req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.SetBasicAuth(c.ClientID, c.ClientSecret) @@ -91,7 +91,7 @@ func (c giteaOauthClient) inspectOauthAccessToken(ctx context.Context, accessTok return nil, err } req.WithContext(ctx) - req.Header.Set("User-Agent", "writefreely") + req.Header.Set("User-Agent", ServerUserAgent("")) req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", "Bearer "+accessToken) diff --git a/oauth_gitlab.go b/oauth_gitlab.go index c9c74aa..ad919e4 100644 --- a/oauth_gitlab.go +++ b/oauth_gitlab.go @@ -63,7 +63,7 @@ func (c gitlabOauthClient) exchangeOauthCode(ctx context.Context, code string) ( return nil, err } req.WithContext(ctx) - req.Header.Set("User-Agent", "writefreely") + req.Header.Set("User-Agent", ServerUserAgent("")) req.Header.Set("Accept", "application/json") req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.SetBasicAuth(c.ClientID, c.ClientSecret) @@ -92,7 +92,7 @@ func (c gitlabOauthClient) inspectOauthAccessToken(ctx context.Context, accessTo return nil, err } req.WithContext(ctx) - req.Header.Set("User-Agent", "writefreely") + req.Header.Set("User-Agent", ServerUserAgent("")) req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", "Bearer "+accessToken) diff --git a/oauth_slack.go b/oauth_slack.go index c881ab6..bad3775 100644 --- a/oauth_slack.go +++ b/oauth_slack.go @@ -111,7 +111,7 @@ func (c slackOauthClient) exchangeOauthCode(ctx context.Context, code string) (* return nil, err } req.WithContext(ctx) - req.Header.Set("User-Agent", "writefreely") + req.Header.Set("User-Agent", ServerUserAgent("")) req.Header.Set("Accept", "application/json") req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.SetBasicAuth(c.ClientID, c.ClientSecret) @@ -140,7 +140,7 @@ func (c slackOauthClient) inspectOauthAccessToken(ctx context.Context, accessTok return nil, err } req.WithContext(ctx) - req.Header.Set("User-Agent", "writefreely") + req.Header.Set("User-Agent", ServerUserAgent("")) req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", "Bearer "+accessToken) diff --git a/oauth_writeas.go b/oauth_writeas.go index 6251a16..e58f6e9 100644 --- a/oauth_writeas.go +++ b/oauth_writeas.go @@ -62,7 +62,7 @@ func (c writeAsOauthClient) exchangeOauthCode(ctx context.Context, code string) return nil, err } req.WithContext(ctx) - req.Header.Set("User-Agent", "writefreely") + req.Header.Set("User-Agent", ServerUserAgent("")) req.Header.Set("Accept", "application/json") req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.SetBasicAuth(c.ClientID, c.ClientSecret) @@ -91,7 +91,7 @@ func (c writeAsOauthClient) inspectOauthAccessToken(ctx context.Context, accessT return nil, err } req.WithContext(ctx) - req.Header.Set("User-Agent", "writefreely") + req.Header.Set("User-Agent", ServerUserAgent("")) req.Header.Set("Accept", "application/json") req.Header.Set("Authorization", "Bearer "+accessToken) diff --git a/pages/landing.tmpl b/pages/landing.tmpl index f968404..2131b40 100644 --- a/pages/landing.tmpl +++ b/pages/landing.tmpl @@ -60,10 +60,8 @@ form dd { margin-top: 0; max-width: 8em; } -#generic-oauth-login { - box-sizing: border-box; - font-size: 17px; - white-space:nowrap; +.or { + margin-bottom: 2.5em !important; } {{end}} @@ -78,20 +76,7 @@ form dd {
or
-or
+These are your linked external accounts.
- {{ range $oauth_account := .OauthAccounts }} -Connect additional accounts to enable logging in with those providers, instead of using your username and password.
-