nidus-sync/sync/oauth.go

94 lines
2.7 KiB
Go
Raw Normal View History

package sync
import (
"net/http"
"net/url"
"strconv"
"github.com/Gleipnir-Technology/nidus-sync/auth"
"github.com/Gleipnir-Technology/nidus-sync/background"
"github.com/Gleipnir-Technology/nidus-sync/config"
"github.com/Gleipnir-Technology/nidus-sync/db/models"
"github.com/Gleipnir-Technology/nidus-sync/htmlpage"
"github.com/rs/zerolog/log"
)
var (
oauthPromptT = buildTemplate("oauth-prompt", "authenticated")
)
type ContextOauthPrompt struct {
User User
}
// Build the ArcGIS authorization URL with PKCE
func buildArcGISAuthURL(clientID string) string {
baseURL := "https://www.arcgis.com/sharing/rest/oauth2/authorize/"
params := url.Values{}
params.Add("client_id", clientID)
params.Add("redirect_uri", config.ArcGISOauthRedirectURL())
params.Add("response_type", "code")
//params.Add("code_challenge", generateCodeChallenge(codeVerifier))
//params.Add("code_challenge_method", "S256")
// See https://developers.arcgis.com/rest/users-groups-and-items/token/
// expiration is defined in minutes
var expiration int
if config.IsProductionEnvironment() {
// 2 weeks is the maximum allowed
expiration = 20160
} else {
expiration = 20
}
params.Add("expiration", strconv.Itoa(expiration))
return baseURL + "?" + params.Encode()
}
func getArcgisOauthBegin(w http.ResponseWriter, r *http.Request) {
authURL := buildArcGISAuthURL(config.ClientID)
http.Redirect(w, r, authURL, http.StatusFound)
}
func getArcgisOauthCallback(w http.ResponseWriter, r *http.Request) {
code := r.URL.Query().Get("code")
log.Info().Str("code", code).Msg("Handling oauth callback")
if code == "" {
respondError(w, "Access code is empty", nil, http.StatusBadRequest)
return
}
user, err := auth.GetAuthenticatedUser(r)
if err != nil {
respondError(w, "You're not currently authenticated, which really shouldn't happen.", err, http.StatusUnauthorized)
return
}
err = background.HandleOauthAccessCode(r.Context(), user, code)
if err != nil {
respondError(w, "Failed to handle access code", err, http.StatusInternalServerError)
return
}
http.Redirect(w, r, config.MakeURLNidus("/"), http.StatusFound)
}
func getOAuthRefresh(w http.ResponseWriter, r *http.Request) {
user, err := auth.GetAuthenticatedUser(r)
if err != nil {
http.Redirect(w, r, "/?next=/oauth/refresh", http.StatusFound)
return
}
oauthPrompt(w, r, user)
}
func oauthPrompt(w http.ResponseWriter, r *http.Request, user *models.User) {
userContent, err := contentForUser(r.Context(), user)
if err != nil {
respondError(w, "Failed to get user content", err, http.StatusInternalServerError)
return
}
data := ContextOauthPrompt{
User: userContent,
}
htmlpage.RenderOrError(w, oauthPromptT, data)
}