OAuth tidy-up and refactorpull/376/head
@@ -304,32 +304,18 @@ func viewLogin(app *App, w http.ResponseWriter, r *http.Request) error { | |||||
p := &struct { | p := &struct { | ||||
page.StaticPage | 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 != "" { | if earlyError != "" { | ||||
@@ -494,7 +494,7 @@ func makeActivityPost(hostName string, p *activitystreams.Person, url string, m | |||||
r, _ := http.NewRequest("POST", url, bytes.NewBuffer(b)) | r, _ := http.NewRequest("POST", url, bytes.NewBuffer(b)) | ||||
r.Header.Add("Content-Type", "application/activity+json") | 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 := sha256.New() | ||||
h.Write(b) | h.Write(b) | ||||
r.Header.Add("Digest", "SHA-256="+base64.StdEncoding.EncodeToString(h.Sum(nil))) | 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, _ := http.NewRequest("GET", url, nil) | ||||
r.Header.Add("Accept", "application/activity+json") | 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 { | if debugging { | ||||
dump, err := httputil.DumpRequestOut(r, true) | dump, err := httputil.DumpRequestOut(r, true) | ||||
@@ -238,27 +238,16 @@ func handleViewLanding(app *App, w http.ResponseWriter, r *http.Request) error { | |||||
p := struct { | p := struct { | ||||
page.StaticPage | page.StaticPage | ||||
*OAuthButtons | |||||
Flashes []template.HTML | Flashes []template.HTML | ||||
Banner template.HTML | Banner template.HTML | ||||
Content template.HTML | Content template.HTML | ||||
ForcedLanding bool | 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) | banner, err := getLandingBanner(app) | ||||
@@ -903,3 +892,13 @@ func adminInitDatabase(app *App) error { | |||||
log.Info("Done.") | log.Info("Done.") | ||||
return nil | 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 + ")" | |||||
} |
@@ -81,6 +81,15 @@ type ( | |||||
CallbackProxyAPI string `ini:"callback_proxy_api"` | 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 { | SlackOauthCfg struct { | ||||
ClientID string `ini:"client_id"` | ClientID string `ini:"client_id"` | ||||
ClientSecret string `ini:"client_secret"` | ClientSecret string `ini:"client_secret"` | ||||
@@ -101,14 +110,6 @@ type ( | |||||
AuthEndpoint string `ini:"auth_endpoint"` | AuthEndpoint string `ini:"auth_endpoint"` | ||||
AllowDisconnect bool `ini:"allow_disconnect"` | 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 holds values that affect how the application functions | ||||
AppCfg struct { | AppCfg struct { | ||||
@@ -165,8 +166,8 @@ type ( | |||||
SlackOauth SlackOauthCfg `ini:"oauth.slack"` | SlackOauth SlackOauthCfg `ini:"oauth.slack"` | ||||
WriteAsOauth WriteAsOauthCfg `ini:"oauth.writeas"` | WriteAsOauth WriteAsOauthCfg `ini:"oauth.writeas"` | ||||
GitlabOauth GitlabOauthCfg `ini:"oauth.gitlab"` | GitlabOauth GitlabOauthCfg `ini:"oauth.gitlab"` | ||||
GenericOauth GenericOauthCfg `ini:"oauth.generic"` | |||||
GiteaOauth GiteaOauthCfg `ini:"oauth.gitea"` | GiteaOauth GiteaOauthCfg `ini:"oauth.gitea"` | ||||
GenericOauth GenericOauthCfg `ini:"oauth.generic"` | |||||
} | } | ||||
) | ) | ||||
@@ -2627,11 +2627,11 @@ func (db *datastore) GetIDForRemoteUser(ctx context.Context, remoteUserID, provi | |||||
} | } | ||||
type oauthAccountInfo struct { | 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) { | func (db *datastore) GetOauthAccounts(ctx context.Context, userID int64) ([]oauthAccountInfo, error) { | ||||
@@ -170,14 +170,14 @@ func handleViewInvite(app *App, w http.ResponseWriter, r *http.Request) error { | |||||
p := struct { | p := struct { | ||||
page.StaticPage | page.StaticPage | ||||
*OAuthButtons | |||||
Error string | Error string | ||||
Flashes []template.HTML | Flashes []template.HTML | ||||
Invite string | 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 { | if expired { | ||||
@@ -9,18 +9,64 @@ | |||||
*/ | */ | ||||
.row.signinbtns { | .row.signinbtns { | ||||
justify-content: space-evenly; | |||||
justify-content: center; | |||||
font-size: 1em; | font-size: 1em; | ||||
margin-top: 2em; | margin-top: 2em; | ||||
margin-bottom: 1em; | margin-bottom: 1em; | ||||
flex-wrap: wrap; | |||||
.loginbtn { | .loginbtn { | ||||
height: 40px; | 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; | |||||
} | |||||
} | |||||
} | } | ||||
} | } | ||||
@@ -30,19 +30,27 @@ import ( | |||||
// OAuthButtons holds display information for different OAuth providers we support. | // OAuthButtons holds display information for different OAuth providers we support. | ||||
type OAuthButtons struct { | 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. | // NewOAuthButtons creates a new OAuthButtons struct based on our app configuration. | ||||
func NewOAuthButtons(cfg *config.Config) *OAuthButtons { | func NewOAuthButtons(cfg *config.Config) *OAuthButtons { | ||||
return &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) | tokenResponse, err := h.oauthClient.exchangeOauthCode(ctx, code) | ||||
if err != nil { | if err != nil { | ||||
log.Error("Unable to exchangeOauthCode: %s", err) | 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()} | return impart.HTTPError{http.StatusInternalServerError, err.Error()} | ||||
} | } | ||||
@@ -408,7 +422,7 @@ func (r *callbackProxyClient) register(ctx context.Context, state string) error | |||||
if err != nil { | if err != nil { | ||||
return err | return err | ||||
} | } | ||||
req.Header.Set("User-Agent", "writefreely") | |||||
req.Header.Set("User-Agent", ServerUserAgent("")) | |||||
req.Header.Set("Accept", "application/json") | req.Header.Set("Accept", "application/json") | ||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | ||||
@@ -62,7 +62,7 @@ func (c genericOauthClient) exchangeOauthCode(ctx context.Context, code string) | |||||
return nil, err | return nil, err | ||||
} | } | ||||
req.WithContext(ctx) | req.WithContext(ctx) | ||||
req.Header.Set("User-Agent", "writefreely") | |||||
req.Header.Set("User-Agent", ServerUserAgent("")) | |||||
req.Header.Set("Accept", "application/json") | req.Header.Set("Accept", "application/json") | ||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | ||||
req.SetBasicAuth(c.ClientID, c.ClientSecret) | req.SetBasicAuth(c.ClientID, c.ClientSecret) | ||||
@@ -91,7 +91,7 @@ func (c genericOauthClient) inspectOauthAccessToken(ctx context.Context, accessT | |||||
return nil, err | return nil, err | ||||
} | } | ||||
req.WithContext(ctx) | req.WithContext(ctx) | ||||
req.Header.Set("User-Agent", "writefreely") | |||||
req.Header.Set("User-Agent", ServerUserAgent("")) | |||||
req.Header.Set("Accept", "application/json") | req.Header.Set("Accept", "application/json") | ||||
req.Header.Set("Authorization", "Bearer "+accessToken) | req.Header.Set("Authorization", "Bearer "+accessToken) | ||||
@@ -62,7 +62,7 @@ func (c giteaOauthClient) exchangeOauthCode(ctx context.Context, code string) (* | |||||
return nil, err | return nil, err | ||||
} | } | ||||
req.WithContext(ctx) | req.WithContext(ctx) | ||||
req.Header.Set("User-Agent", "writefreely") | |||||
req.Header.Set("User-Agent", ServerUserAgent("")) | |||||
req.Header.Set("Accept", "application/json") | req.Header.Set("Accept", "application/json") | ||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | ||||
req.SetBasicAuth(c.ClientID, c.ClientSecret) | req.SetBasicAuth(c.ClientID, c.ClientSecret) | ||||
@@ -91,7 +91,7 @@ func (c giteaOauthClient) inspectOauthAccessToken(ctx context.Context, accessTok | |||||
return nil, err | return nil, err | ||||
} | } | ||||
req.WithContext(ctx) | req.WithContext(ctx) | ||||
req.Header.Set("User-Agent", "writefreely") | |||||
req.Header.Set("User-Agent", ServerUserAgent("")) | |||||
req.Header.Set("Accept", "application/json") | req.Header.Set("Accept", "application/json") | ||||
req.Header.Set("Authorization", "Bearer "+accessToken) | req.Header.Set("Authorization", "Bearer "+accessToken) | ||||
@@ -63,7 +63,7 @@ func (c gitlabOauthClient) exchangeOauthCode(ctx context.Context, code string) ( | |||||
return nil, err | return nil, err | ||||
} | } | ||||
req.WithContext(ctx) | req.WithContext(ctx) | ||||
req.Header.Set("User-Agent", "writefreely") | |||||
req.Header.Set("User-Agent", ServerUserAgent("")) | |||||
req.Header.Set("Accept", "application/json") | req.Header.Set("Accept", "application/json") | ||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | ||||
req.SetBasicAuth(c.ClientID, c.ClientSecret) | req.SetBasicAuth(c.ClientID, c.ClientSecret) | ||||
@@ -92,7 +92,7 @@ func (c gitlabOauthClient) inspectOauthAccessToken(ctx context.Context, accessTo | |||||
return nil, err | return nil, err | ||||
} | } | ||||
req.WithContext(ctx) | req.WithContext(ctx) | ||||
req.Header.Set("User-Agent", "writefreely") | |||||
req.Header.Set("User-Agent", ServerUserAgent("")) | |||||
req.Header.Set("Accept", "application/json") | req.Header.Set("Accept", "application/json") | ||||
req.Header.Set("Authorization", "Bearer "+accessToken) | req.Header.Set("Authorization", "Bearer "+accessToken) | ||||
@@ -111,7 +111,7 @@ func (c slackOauthClient) exchangeOauthCode(ctx context.Context, code string) (* | |||||
return nil, err | return nil, err | ||||
} | } | ||||
req.WithContext(ctx) | req.WithContext(ctx) | ||||
req.Header.Set("User-Agent", "writefreely") | |||||
req.Header.Set("User-Agent", ServerUserAgent("")) | |||||
req.Header.Set("Accept", "application/json") | req.Header.Set("Accept", "application/json") | ||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | ||||
req.SetBasicAuth(c.ClientID, c.ClientSecret) | req.SetBasicAuth(c.ClientID, c.ClientSecret) | ||||
@@ -140,7 +140,7 @@ func (c slackOauthClient) inspectOauthAccessToken(ctx context.Context, accessTok | |||||
return nil, err | return nil, err | ||||
} | } | ||||
req.WithContext(ctx) | req.WithContext(ctx) | ||||
req.Header.Set("User-Agent", "writefreely") | |||||
req.Header.Set("User-Agent", ServerUserAgent("")) | |||||
req.Header.Set("Accept", "application/json") | req.Header.Set("Accept", "application/json") | ||||
req.Header.Set("Authorization", "Bearer "+accessToken) | req.Header.Set("Authorization", "Bearer "+accessToken) | ||||
@@ -62,7 +62,7 @@ func (c writeAsOauthClient) exchangeOauthCode(ctx context.Context, code string) | |||||
return nil, err | return nil, err | ||||
} | } | ||||
req.WithContext(ctx) | req.WithContext(ctx) | ||||
req.Header.Set("User-Agent", "writefreely") | |||||
req.Header.Set("User-Agent", ServerUserAgent("")) | |||||
req.Header.Set("Accept", "application/json") | req.Header.Set("Accept", "application/json") | ||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | ||||
req.SetBasicAuth(c.ClientID, c.ClientSecret) | req.SetBasicAuth(c.ClientID, c.ClientSecret) | ||||
@@ -91,7 +91,7 @@ func (c writeAsOauthClient) inspectOauthAccessToken(ctx context.Context, accessT | |||||
return nil, err | return nil, err | ||||
} | } | ||||
req.WithContext(ctx) | req.WithContext(ctx) | ||||
req.Header.Set("User-Agent", "writefreely") | |||||
req.Header.Set("User-Agent", ServerUserAgent("")) | |||||
req.Header.Set("Accept", "application/json") | req.Header.Set("Accept", "application/json") | ||||
req.Header.Set("Authorization", "Bearer "+accessToken) | req.Header.Set("Authorization", "Bearer "+accessToken) | ||||
@@ -60,10 +60,8 @@ form dd { | |||||
margin-top: 0; | margin-top: 0; | ||||
max-width: 8em; | max-width: 8em; | ||||
} | } | ||||
#generic-oauth-login { | |||||
box-sizing: border-box; | |||||
font-size: 17px; | |||||
white-space:nowrap; | |||||
.or { | |||||
margin-bottom: 2.5em !important; | |||||
} | } | ||||
</style> | </style> | ||||
{{end}} | {{end}} | ||||
@@ -78,20 +76,7 @@ form dd { | |||||
<div{{if not .OpenRegistration}} style="padding: 2em 0;"{{end}}> | <div{{if not .OpenRegistration}} style="padding: 2em 0;"{{end}}> | ||||
{{ if .OpenRegistration }} | {{ if .OpenRegistration }} | ||||
{{ if or .OauthSlack .OauthWriteAs .OauthGitlab .OauthGeneric }} | |||||
{{ if .OauthSlack }} | |||||
<div class="row content-container signinbtns signinoauthbtns"><a class="loginbtn" href="/oauth/slack"><img alt="Sign in with Slack" height="40" width="172" src="/img/sign_in_with_slack.png" srcset="/img/sign_in_with_slack.png 1x, /img/sign_in_with_slack@2x.png 2x" /></a></div> | |||||
{{ end }} | |||||
{{ if .OauthWriteAs }} | |||||
<div class="row content-container signinbtns signinoauthbtns"><a class="btn cta loginbtn" id="writeas-login" href="/oauth/write.as">Sign in with <strong>Write.as</strong></a></div> | |||||
{{ end }} | |||||
{{ if .OauthGitlab }} | |||||
<div class="row content-container signinbtns signinoauthbtns"><a class="btn cta loginbtn" id="gitlab-login" href="/oauth/gitlab">Sign in with <strong>{{.GitlabDisplayName}}</strong></a></div> | |||||
{{ end }} | |||||
{{ if .OauthGeneric }} | |||||
<div class="row content-container signinbtns signinoauthbtns"><a class="btn cta loginbtn" id="generic-oauth-login" href="/oauth/generic">Sign in with <strong>{{ .OauthGenericDisplayName }}</strong></a></div> | |||||
{{ end }} | |||||
{{ end }} | |||||
{{template "oauth-buttons" .}} | |||||
{{if not .DisablePasswordAuth}} | {{if not .DisablePasswordAuth}} | ||||
{{if .Flashes}}<ul class="errors"> | {{if .Flashes}}<ul class="errors"> | ||||
{{range .Flashes}}<li class="urgent">{{.}}</li>{{end}} | {{range .Flashes}}<li class="urgent">{{.}}</li>{{end}} | ||||
@@ -3,10 +3,6 @@ | |||||
<meta itemprop="description" content="Log in to {{.SiteName}}."> | <meta itemprop="description" content="Log in to {{.SiteName}}."> | ||||
<style> | <style> | ||||
input{margin-bottom:0.5em;} | input{margin-bottom:0.5em;} | ||||
#generic-oauth-login { | |||||
box-sizing: border-box; | |||||
font-size: 17px; | |||||
} | |||||
</style> | </style> | ||||
{{end}} | {{end}} | ||||
{{define "content"}} | {{define "content"}} | ||||
@@ -17,32 +13,7 @@ input{margin-bottom:0.5em;} | |||||
{{range .Flashes}}<li class="urgent">{{.}}</li>{{end}} | {{range .Flashes}}<li class="urgent">{{.}}</li>{{end}} | ||||
</ul>{{end}} | </ul>{{end}} | ||||
{{ if or .OauthSlack .OauthWriteAs .OauthGitlab .OauthGeneric .OauthGitea }} | |||||
<div class="row content-container signinbtns"> | |||||
{{ if .OauthSlack }} | |||||
<a class="loginbtn" href="/oauth/slack"><img alt="Sign in with Slack" height="40" width="172" src="/img/sign_in_with_slack.png" srcset="/img/sign_in_with_slack.png 1x, /img/sign_in_with_slack@2x.png 2x" /></a> | |||||
{{ end }} | |||||
{{ if .OauthWriteAs }} | |||||
<a class="btn cta loginbtn" id="writeas-login" href="/oauth/write.as">Sign in with <strong>Write.as</strong></a> | |||||
{{ end }} | |||||
{{ if .OauthGitlab }} | |||||
<a class="btn cta loginbtn" id="gitlab-login" href="/oauth/gitlab">Sign in with <strong>{{.GitlabDisplayName}}</strong></a> | |||||
{{ end }} | |||||
{{ if .OauthGeneric }} | |||||
<a class="btn cta loginbtn" id="generic-oauth-login" href="/oauth/generic">Sign in with <strong>{{ .OauthGenericDisplayName }}</strong></a> | |||||
{{ end }} | |||||
{{ if .OauthGitea }} | |||||
<a class="btn cta loginbtn" id="gitea-login" href="/oauth/gitea">Sign in with <strong>{{.GiteaDisplayName}}</strong></a> | |||||
{{ end }} | |||||
</div> | |||||
{{if not .DisablePasswordAuth}} | |||||
<div class="or"> | |||||
<p>or</p> | |||||
<hr class="short" /> | |||||
</div> | |||||
{{end}} | |||||
{{ end }} | |||||
{{template "oauth-buttons" .}} | |||||
{{if not .DisablePasswordAuth}} | {{if not .DisablePasswordAuth}} | ||||
<form action="/auth/login" method="post" style="text-align: center;margin-top:1em;" onsubmit="disableSubmit()"> | <form action="/auth/login" method="post" style="text-align: center;margin-top:1em;" onsubmit="disableSubmit()"> | ||||
@@ -70,25 +70,9 @@ form dd { | |||||
</ul>{{end}} | </ul>{{end}} | ||||
<div id="billing"> | <div id="billing"> | ||||
{{ if or .OAuth.SlackEnabled .OAuth.WriteAsEnabled .OAuth.GitLabEnabled }} | |||||
<div class="row content-container signinbtns"> | |||||
{{ if .OAuth.SlackEnabled }} | |||||
<a class="loginbtn" href="/oauth/slack{{if .Invite}}?invite_code={{.Invite}}{{end}}"><img alt="Sign in with Slack" height="40" width="172" src="/img/sign_in_with_slack.png" srcset="/img/sign_in_with_slack.png 1x, /img/sign_in_with_slack@2x.png 2x" /></a> | |||||
{{ end }} | |||||
{{ if .OAuth.WriteAsEnabled }} | |||||
<a class="btn cta loginbtn" id="writeas-login" href="/oauth/write.as{{if .Invite}}?invite_code={{.Invite}}{{end}}">Sign in with <strong>Write.as</strong></a> | |||||
{{ end }} | |||||
{{ if .OAuth.GitLabEnabled }} | |||||
<a class="btn cta loginbtn" id="gitlab-login" href="/oauth/gitlab{{if .Invite}}?invite_code={{.Invite}}{{end}}">Sign in with <strong>{{.OAuth.GitLabDisplayName}}</strong></a> | |||||
{{ end }} | |||||
</div> | |||||
<div class="or"> | |||||
<p>or</p> | |||||
<hr class="short" /> | |||||
</div> | |||||
{{ end }} | |||||
{{template "oauth-buttons" .}} | |||||
{{if not .DisablePasswordAuth}} | |||||
<form action="/auth/signup" method="POST" id="signup-form" onsubmit="return signup()"> | <form action="/auth/signup" method="POST" id="signup-form" onsubmit="return signup()"> | ||||
<input type="hidden" name="invite_code" value="{{.Invite}}" /> | <input type="hidden" name="invite_code" value="{{.Invite}}" /> | ||||
<dl class="billing"> | <dl class="billing"> | ||||
@@ -112,6 +96,7 @@ form dd { | |||||
</dt> | </dt> | ||||
</dl> | </dl> | ||||
</form> | </form> | ||||
{{end}} | |||||
</div> | </div> | ||||
{{ end }} | {{ end }} | ||||
</div> | </div> | ||||
@@ -85,12 +85,18 @@ func initPage(parentDir, path, key string) { | |||||
log.Info(" [%s] %s", key, path) | log.Info(" [%s] %s", key, path) | ||||
} | } | ||||
pages[key] = template.Must(template.New("").Funcs(funcMap).ParseFiles( | |||||
files := []string{ | |||||
path, | path, | ||||
filepath.Join(parentDir, templatesDir, "include", "footer.tmpl"), | filepath.Join(parentDir, templatesDir, "include", "footer.tmpl"), | ||||
filepath.Join(parentDir, templatesDir, "base.tmpl"), | filepath.Join(parentDir, templatesDir, "base.tmpl"), | ||||
filepath.Join(parentDir, templatesDir, "user", "include", "silenced.tmpl"), | filepath.Join(parentDir, templatesDir, "user", "include", "silenced.tmpl"), | ||||
)) | |||||
} | |||||
if key == "login.tmpl" || key == "landing.tmpl" || key == "signup.tmpl" { | |||||
files = append(files, filepath.Join(parentDir, templatesDir, "include", "oauth.tmpl")) | |||||
} | |||||
pages[key] = template.Must(template.New("").Funcs(funcMap).ParseFiles(files...)) | |||||
} | } | ||||
func initUserPage(parentDir, path, key string) { | func initUserPage(parentDir, path, key string) { | ||||
@@ -0,0 +1,37 @@ | |||||
{{define "oauth-buttons"}} | |||||
{{ if or .SlackEnabled .WriteAsEnabled .GitLabEnabled .GiteaEnabled .GenericEnabled }} | |||||
<div class="row content-container signinbtns"> | |||||
{{ if .SlackEnabled }} | |||||
<a class="loginbtn" href="/oauth/slack"><img alt="Sign in with Slack" height="40" width="172" src="/img/sign_in_with_slack.png" srcset="/img/sign_in_with_slack.png 1x, /img/sign_in_with_slack@2x.png 2x" /></a> | |||||
{{ end }} | |||||
{{ if .WriteAsEnabled }} | |||||
<a class="btn cta loginbtn" id="writeas-login" href="/oauth/write.as"> | |||||
<img src="/img/mark/writeas-white.png" /> | |||||
Sign in with <strong>Write.as</strong> | |||||
</a> | |||||
{{ end }} | |||||
{{ if .GitLabEnabled }} | |||||
<a class="btn cta loginbtn" id="gitlab-login" href="/oauth/gitlab"> | |||||
<img src="/img/mark/gitlab.png" /> | |||||
Sign in with <strong>{{.GitLabDisplayName}}</strong> | |||||
</a> | |||||
{{ end }} | |||||
{{ if .GiteaEnabled }} | |||||
<a class="btn cta loginbtn" id="gitea-login" href="/oauth/gitea"> | |||||
<img src="/img/mark/gitea.png" /> | |||||
Sign in with <strong>{{.GiteaDisplayName}}</strong> | |||||
</a> | |||||
{{ end }} | |||||
{{ if .GenericEnabled }} | |||||
<a class="btn cta loginbtn" id="generic-oauth-login" href="/oauth/generic">Sign in with <strong>{{.GenericDisplayName}}</strong></a> | |||||
{{ end }} | |||||
</div> | |||||
{{if not .DisablePasswordAuth}} | |||||
<div class="or"> | |||||
<p>or</p> | |||||
<hr class="short" /> | |||||
</div> | |||||
{{end}} | |||||
{{ end }} | |||||
{{end}} |
@@ -75,18 +75,18 @@ h3 { font-weight: normal; } | |||||
</form> | </form> | ||||
{{end}} | {{end}} | ||||
{{ if .OauthSection }} | |||||
{{ if .OauthSection }} | |||||
<hr /> | <hr /> | ||||
{{ if .OauthAccounts }} | |||||
{{ if .OauthAccounts }} | |||||
<div class="option"> | <div class="option"> | ||||
<h2>Linked Accounts</h2> | <h2>Linked Accounts</h2> | ||||
<p>These are your linked external accounts.</p> | <p>These are your linked external accounts.</p> | ||||
{{ range $oauth_account := .OauthAccounts }} | |||||
<form method="post" action="/api/me/oauth/remove" autocomplete="false"> | |||||
<input type="hidden" name="provider" value="{{ $oauth_account.Provider }}" /> | |||||
<input type="hidden" name="client_id" value="{{ $oauth_account.ClientID }}" /> | |||||
<input type="hidden" name="remote_user_id" value="{{ $oauth_account.RemoteUserID }}" /> | |||||
{{ range $oauth_account := .OauthAccounts }} | |||||
<form method="post" action="/api/me/oauth/remove" autocomplete="false"> | |||||
<input type="hidden" name="provider" value="{{ $oauth_account.Provider }}" /> | |||||
<input type="hidden" name="client_id" value="{{ $oauth_account.ClientID }}" /> | |||||
<input type="hidden" name="remote_user_id" value="{{ $oauth_account.RemoteUserID }}" /> | |||||
<div class="section oauth-provider"> | <div class="section oauth-provider"> | ||||
{{ if $oauth_account.DisplayName}} | {{ if $oauth_account.DisplayName}} | ||||
{{ if $oauth_account.AllowDisconnect}} | {{ if $oauth_account.AllowDisconnect}} | ||||
@@ -99,58 +99,58 @@ h3 { font-weight: normal; } | |||||
<input type="submit" value="Remove {{ $oauth_account.Provider | title }}" /> | <input type="submit" value="Remove {{ $oauth_account.Provider | title }}" /> | ||||
{{end}} | {{end}} | ||||
</div> | </div> | ||||
</form> | |||||
{{ end }} | |||||
</form> | |||||
{{ end }} | |||||
</div> | </div> | ||||
{{ end }} | {{ end }} | ||||
{{ if or .OauthSlack .OauthWriteAs .OauthGitLab .OauthGeneric .OauthGitea }} | {{ if or .OauthSlack .OauthWriteAs .OauthGitLab .OauthGeneric .OauthGitea }} | ||||
<div class="option"> | <div class="option"> | ||||
<h2>Link External Accounts</h2> | <h2>Link External Accounts</h2> | ||||
<p>Connect additional accounts to enable logging in with those providers, instead of using your username and password.</p> | <p>Connect additional accounts to enable logging in with those providers, instead of using your username and password.</p> | ||||
<div class="row"> | |||||
<div class="row signinbtns"> | |||||
{{ if .OauthWriteAs }} | {{ if .OauthWriteAs }} | ||||
<div class="section oauth-provider"> | <div class="section oauth-provider"> | ||||
<img src="/img/mark/writeas.png" alt="Write.as" /> | |||||
<a class="btn cta loginbtn" id="writeas-login" href="/oauth/write.as?attach=t"> | <a class="btn cta loginbtn" id="writeas-login" href="/oauth/write.as?attach=t"> | ||||
<img src="/img/mark/writeas-white.png" alt="Write.as" /> | |||||
Link <strong>Write.as</strong> | Link <strong>Write.as</strong> | ||||
</a> | </a> | ||||
</div> | </div> | ||||
{{ end }} | {{ end }} | ||||
{{ if .OauthSlack }} | |||||
{{ if .OauthSlack }} | |||||
<div class="section oauth-provider"> | <div class="section oauth-provider"> | ||||
<img src="/img/mark/slack.png" alt="Slack" /> | |||||
<a class="btn cta loginbtn" href="/oauth/slack?attach=t"> | |||||
<a class="btn cta loginbtn" id="slack-login" href="/oauth/slack?attach=t"> | |||||
<img src="/img/mark/slack.png" alt="Slack" /> | |||||
Link <strong>Slack</strong> | Link <strong>Slack</strong> | ||||
</a> | </a> | ||||
</div> | </div> | ||||
{{ end }} | |||||
{{ if .OauthGitLab }} | |||||
{{ end }} | |||||
{{ if .OauthGitLab }} | |||||
<div class="section oauth-provider"> | <div class="section oauth-provider"> | ||||
<img src="/img/mark/gitlab.png" alt="GitLab" /> | |||||
<a class="btn cta loginbtn" id="gitlab-login" href="/oauth/gitlab?attach=t"> | <a class="btn cta loginbtn" id="gitlab-login" href="/oauth/gitlab?attach=t"> | ||||
<img src="/img/mark/gitlab.png" alt="GitLab" /> | |||||
Link <strong>{{.GitLabDisplayName}}</strong> | Link <strong>{{.GitLabDisplayName}}</strong> | ||||
</a> | </a> | ||||
</div> | </div> | ||||
{{ end }} | |||||
{{ if .OauthGitea }} | |||||
{{ end }} | |||||
{{ if .OauthGitea }} | |||||
<div class="section oauth-provider"> | <div class="section oauth-provider"> | ||||
<img src="/img/mark/gitea.png" alt="Gitea" /> | |||||
<a class="btn cta loginbtn" id="gitea-login" href="/oauth/gitea?attach=t"> | <a class="btn cta loginbtn" id="gitea-login" href="/oauth/gitea?attach=t"> | ||||
<img src="/img/mark/gitea.png" alt="Gitea" /> | |||||
Link <strong>{{.GiteaDisplayName}}</strong> | Link <strong>{{.GiteaDisplayName}}</strong> | ||||
</a> | </a> | ||||
</div> | </div> | ||||
{{ end }} | |||||
</div> | |||||
{{ if .OauthGeneric }} | |||||
<div class="row"> | |||||
<div class="section oauth-provider"> | |||||
<p><a class="btn cta loginbtn" id="generic-oauth-login" href="/oauth/generic?attach=t">Link <strong>{{ .OauthGenericDisplayName }}</strong></a></p> | |||||
</div> | |||||
{{ end }} | |||||
{{ if .OauthGeneric }} | |||||
<div class="section oauth-provider"> | |||||
<a class="btn cta loginbtn" id="generic-oauth-login" href="/oauth/generic?attach=t"> | |||||
Link <strong>{{ .OauthGenericDisplayName }}</strong> | |||||
</a> | |||||
</div> | </div> | ||||
{{ end }} | |||||
{{ end }} | |||||
</div> | |||||
</div> | </div> | ||||
{{ end }} | {{ end }} | ||||
{{ end }} | |||||
{{ end }} | |||||
</div> | </div> | ||||
<script> | <script> | ||||