Merge pull request #21 from fossyy/staging
Handle Google OAuth2 error on callback
This commit is contained in:
@ -31,6 +31,7 @@ const (
|
|||||||
|
|
||||||
type Database interface {
|
type Database interface {
|
||||||
IsUserRegistered(email string, username string) bool
|
IsUserRegistered(email string, username string) bool
|
||||||
|
IsEmailRegistered(email string) bool
|
||||||
|
|
||||||
CreateUser(user *models.User) error
|
CreateUser(user *models.User) error
|
||||||
GetUser(email string) (*models.User, error)
|
GetUser(email string) (*models.User, error)
|
||||||
@ -149,6 +150,18 @@ func (db *mySQLdb) IsUserRegistered(email string, username string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *mySQLdb) IsEmailRegistered(email string) bool {
|
||||||
|
var data models.User
|
||||||
|
err := db.DB.Table("users").Where("email = ? ", email).First(&data).Error
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (db *mySQLdb) CreateUser(user *models.User) error {
|
func (db *mySQLdb) CreateUser(user *models.User) error {
|
||||||
err := db.DB.Create(user).Error
|
err := db.DB.Create(user).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -240,6 +253,18 @@ func (db *postgresDB) IsUserRegistered(email string, username string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *postgresDB) IsEmailRegistered(email string) bool {
|
||||||
|
var data models.User
|
||||||
|
err := db.DB.Table("users").Where("email = $1 ", email).First(&data).Error
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (db *postgresDB) CreateUser(user *models.User) error {
|
func (db *postgresDB) CreateUser(user *models.User) error {
|
||||||
err := db.DB.Create(user).Error
|
err := db.DB.Create(user).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -91,6 +91,11 @@ func GET(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
delete(CsrfTokens, r.URL.Query().Get("state"))
|
delete(CsrfTokens, r.URL.Query().Get("state"))
|
||||||
|
|
||||||
|
if err := r.URL.Query().Get("error"); err != "" {
|
||||||
|
http.Redirect(w, r, fmt.Sprintf("/signin?error=%s", err), http.StatusFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
formData := url.Values{
|
formData := url.Values{
|
||||||
"grant_type": {"authorization_code"},
|
"grant_type": {"authorization_code"},
|
||||||
"code": {r.URL.Query().Get("code")},
|
"code": {r.URL.Query().Get("code")},
|
||||||
@ -98,6 +103,7 @@ func GET(w http.ResponseWriter, r *http.Request) {
|
|||||||
"client_secret": {utils.Getenv("GOOGLE_CLIENT_SECRET")},
|
"client_secret": {utils.Getenv("GOOGLE_CLIENT_SECRET")},
|
||||||
"redirect_uri": {utils.Getenv("GOOGLE_CALLBACK")},
|
"redirect_uri": {utils.Getenv("GOOGLE_CALLBACK")},
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := http.Post("https://oauth2.googleapis.com/token", "application/x-www-form-urlencoded", bytes.NewBufferString(formData.Encode()))
|
resp, err := http.Post("https://oauth2.googleapis.com/token", "application/x-www-form-urlencoded", bytes.NewBufferString(formData.Encode()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Error:", err)
|
log.Error("Error:", err)
|
||||||
@ -135,11 +141,15 @@ func GET(w http.ResponseWriter, r *http.Request) {
|
|||||||
response, err := http.Post("https://oauth2.googleapis.com/revoke", "application/json", bytes.NewBuffer(requestBody))
|
response, err := http.Post("https://oauth2.googleapis.com/revoke", "application/json", bytes.NewBuffer(requestBody))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Error revoking access token: ", err)
|
log.Error("Error revoking access token: ", err)
|
||||||
|
http.Error(w, "Failed to revoke access token", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
|
|
||||||
if response.StatusCode != http.StatusOK {
|
if response.StatusCode != http.StatusOK {
|
||||||
log.Error("Error revoking access token: ", response.StatusCode)
|
log.Error("Error revoking access token: ", response.StatusCode)
|
||||||
|
http.Error(w, "Failed to revoke access token", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var oauthUser OauthUser
|
var oauthUser OauthUser
|
||||||
@ -149,7 +159,13 @@ func GET(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !db.DB.IsUserRegistered(oauthUser.Email, "ll") {
|
if oauthUser.Email == "" {
|
||||||
|
log.Error("Error reading user info response body: email not found")
|
||||||
|
http.Error(w, "Invalid email is given", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !db.DB.IsEmailRegistered(oauthUser.Email) {
|
||||||
code := utils.GenerateRandomString(64)
|
code := utils.GenerateRandomString(64)
|
||||||
googleOauthSetupHandler.SetupUser[code] = &googleOauthSetupHandler.UnregisteredUser{
|
googleOauthSetupHandler.SetupUser[code] = &googleOauthSetupHandler.UnregisteredUser{
|
||||||
Code: code,
|
Code: code,
|
||||||
@ -167,6 +183,7 @@ func GET(w http.ResponseWriter, r *http.Request) {
|
|||||||
log.Error(err.Error())
|
log.Error(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
storeSession := session.Create()
|
storeSession := session.Create()
|
||||||
storeSession.Values["user"] = types.User{
|
storeSession.Values["user"] = types.User{
|
||||||
UserID: user.UserID,
|
UserID: user.UserID,
|
||||||
|
@ -2,6 +2,7 @@ package signinHandler
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"github.com/a-h/templ"
|
||||||
"github.com/fossyy/filekeeper/cache"
|
"github.com/fossyy/filekeeper/cache"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
@ -14,16 +15,49 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var log *logger.AggregatedLogger
|
var log *logger.AggregatedLogger
|
||||||
|
var errorMessages = make(map[string]string)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
errorMessages = map[string]string{
|
||||||
|
"redirect_uri_mismatch": "The redirect URI provided does not match the one registered with our service. Please contact the administrator for assistance.",
|
||||||
|
"invalid_request": "The request is missing required parameters or has invalid values. Please try again or contact support for assistance.",
|
||||||
|
"access_denied": "Access was denied. You may have declined the request for permission. Please try again if you wish to grant access.",
|
||||||
|
"unauthorized_client": "You are not authorized to make this request. Please contact support for further assistance.",
|
||||||
|
"unsupported_response_type": "The requested response type is not supported. Please try again with a supported response type.",
|
||||||
|
"invalid_scope": "The requested scope is invalid or unknown. Please try again or contact support for assistance.",
|
||||||
|
"server_error": "Our server encountered an unexpected error. Please try again later or contact support for assistance.",
|
||||||
|
"temporarily_unavailable": "Our server is currently undergoing maintenance. Please try again later.",
|
||||||
|
"invalid_grant": "The authorization code or refresh token provided is invalid. Please try again or contact support for assistance.",
|
||||||
|
"invalid_client": "The client identifier provided is invalid. Please check your credentials and try again.",
|
||||||
|
"invalid_token": "The access token provided is invalid. Please try again or contact support for assistance.",
|
||||||
|
"insufficient_scope": "You do not have sufficient privileges to perform this action. Please contact support for assistance.",
|
||||||
|
"interaction_required": "Interaction with the authorization server is required. Please try again.",
|
||||||
|
"login_required": "You need to log in again to proceed. Please try logging in again.",
|
||||||
|
"account_selection_required": "Please select an account to proceed with the request.",
|
||||||
|
"consent_required": "Consent is required to proceed. Please provide consent to continue.",
|
||||||
|
}
|
||||||
log = logger.Logger()
|
log = logger.Logger()
|
||||||
}
|
}
|
||||||
|
|
||||||
func GET(w http.ResponseWriter, r *http.Request) {
|
func GET(w http.ResponseWriter, r *http.Request) {
|
||||||
component := signinView.Main("Sign in Page", types.Message{
|
var component templ.Component
|
||||||
|
if err := r.URL.Query().Get("error"); err != "" {
|
||||||
|
message, ok := errorMessages[err]
|
||||||
|
if !ok {
|
||||||
|
message = "Unknown error occurred. Please contact support at bagas@fossy.my.id for assistance."
|
||||||
|
}
|
||||||
|
|
||||||
|
component = signinView.Main("Sign in Page", types.Message{
|
||||||
|
Code: 0,
|
||||||
|
Message: message,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
component = signinView.Main("Sign in Page", types.Message{
|
||||||
Code: 3,
|
Code: 3,
|
||||||
Message: "",
|
Message: "",
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
err := component.Render(r.Context(), w)
|
err := component.Render(r.Context(), w)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
@ -16,11 +16,11 @@ templ form(err types.Message, title string) {
|
|||||||
switch err.Code {
|
switch err.Code {
|
||||||
case 0:
|
case 0:
|
||||||
<div class="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400" role="alert">
|
<div class="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400" role="alert">
|
||||||
<span class="font-medium">Danger alert!</span> {err.Message}
|
{err.Message}
|
||||||
</div>
|
</div>
|
||||||
case 1:
|
case 1:
|
||||||
<div class="p-4 mb-4 text-sm text-green-800 rounded-lg bg-green-50 dark:bg-gray-800 dark:text-green-400" role="alert">
|
<div class="p-4 mb-4 text-sm text-green-800 rounded-lg bg-green-50 dark:bg-gray-800 dark:text-green-400" role="alert">
|
||||||
<span class="font-medium">Success alert!</span> {err.Message}
|
{err.Message}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,7 +16,7 @@ templ content(title string, err types.Message) {
|
|||||||
switch err.Code {
|
switch err.Code {
|
||||||
case 0:
|
case 0:
|
||||||
<div class="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400" role="alert">
|
<div class="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400" role="alert">
|
||||||
<span class="font-medium">Danger alert!</span> {err.Message}
|
{err.Message}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@ -50,7 +50,7 @@ templ NewPasswordForm(title string, err types.Message) {
|
|||||||
switch err.Code {
|
switch err.Code {
|
||||||
case 0:
|
case 0:
|
||||||
<div class="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400" role="alert">
|
<div class="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400" role="alert">
|
||||||
<span class="font-medium">Danger alert!</span> {err.Message}
|
{err.Message}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,7 +16,7 @@ templ content(err types.Message, title string) {
|
|||||||
switch err.Code {
|
switch err.Code {
|
||||||
case 0:
|
case 0:
|
||||||
<div class="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400" role="alert">
|
<div class="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400" role="alert">
|
||||||
<span class="font-medium">Danger alert!</span> {err.Message}
|
{err.Message}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,11 +16,11 @@ templ form(err types.Message, title string) {
|
|||||||
switch err.Code {
|
switch err.Code {
|
||||||
case 0:
|
case 0:
|
||||||
<div class="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400" role="alert">
|
<div class="p-4 mb-4 text-sm text-red-800 rounded-lg bg-red-50 dark:bg-gray-800 dark:text-red-400" role="alert">
|
||||||
<span class="font-medium">Danger alert!</span> {err.Message}
|
{err.Message}
|
||||||
</div>
|
</div>
|
||||||
case 1:
|
case 1:
|
||||||
<div class="p-4 mb-4 text-sm text-green-800 rounded-lg bg-green-50 dark:bg-gray-800 dark:text-green-400" role="alert">
|
<div class="p-4 mb-4 text-sm text-green-800 rounded-lg bg-green-50 dark:bg-gray-800 dark:text-green-400" role="alert">
|
||||||
<span class="font-medium">Success alert!</span> {err.Message}
|
{err.Message}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user