Add first login route

This commit is contained in:
Achim Rohn
2025-09-17 16:30:18 +02:00
parent 2a3506d21b
commit 8bc7b1e27b
9 changed files with 104 additions and 21 deletions
+2 -2
View File
@@ -5,8 +5,8 @@ package ent
import (
"encoding/json"
"ersteller-lib/starter/ent/googleauth"
"ersteller-lib/starter/ent/schema"
"ersteller-lib/starter/ent/user"
"ersteller-lib/starter/google"
"fmt"
"strings"
"time"
@@ -25,7 +25,7 @@ type GoogleAuth struct {
// UpdatedAt holds the value of the "updated_at" field.
UpdatedAt time.Time `json:"updated_at,omitempty"`
// Credentials holds the value of the "credentials" field.
Credentials google.Credentials `json:"credentials,omitempty"`
Credentials schema.Credentials `json:"credentials,omitempty"`
// Edges holds the relations/edges for other nodes in the graph.
// The values are being populated by the GoogleAuthQuery when eager-loading is set.
Edges GoogleAuthEdges `json:"edges"`
+2 -2
View File
@@ -6,8 +6,8 @@ import (
"context"
"errors"
"ersteller-lib/starter/ent/googleauth"
"ersteller-lib/starter/ent/schema"
"ersteller-lib/starter/ent/user"
"ersteller-lib/starter/google"
"fmt"
"time"
@@ -51,7 +51,7 @@ func (_c *GoogleAuthCreate) SetNillableUpdatedAt(v *time.Time) *GoogleAuthCreate
}
// SetCredentials sets the "credentials" field.
func (_c *GoogleAuthCreate) SetCredentials(v google.Credentials) *GoogleAuthCreate {
func (_c *GoogleAuthCreate) SetCredentials(v schema.Credentials) *GoogleAuthCreate {
_c.mutation.SetCredentials(v)
return _c
}
+5 -5
View File
@@ -7,8 +7,8 @@ import (
"errors"
"ersteller-lib/starter/ent/googleauth"
"ersteller-lib/starter/ent/predicate"
"ersteller-lib/starter/ent/schema"
"ersteller-lib/starter/ent/user"
"ersteller-lib/starter/google"
"fmt"
"time"
@@ -37,13 +37,13 @@ func (_u *GoogleAuthUpdate) SetUpdatedAt(v time.Time) *GoogleAuthUpdate {
}
// SetCredentials sets the "credentials" field.
func (_u *GoogleAuthUpdate) SetCredentials(v google.Credentials) *GoogleAuthUpdate {
func (_u *GoogleAuthUpdate) SetCredentials(v schema.Credentials) *GoogleAuthUpdate {
_u.mutation.SetCredentials(v)
return _u
}
// SetNillableCredentials sets the "credentials" field if the given value is not nil.
func (_u *GoogleAuthUpdate) SetNillableCredentials(v *google.Credentials) *GoogleAuthUpdate {
func (_u *GoogleAuthUpdate) SetNillableCredentials(v *schema.Credentials) *GoogleAuthUpdate {
if v != nil {
_u.SetCredentials(*v)
}
@@ -190,13 +190,13 @@ func (_u *GoogleAuthUpdateOne) SetUpdatedAt(v time.Time) *GoogleAuthUpdateOne {
}
// SetCredentials sets the "credentials" field.
func (_u *GoogleAuthUpdateOne) SetCredentials(v google.Credentials) *GoogleAuthUpdateOne {
func (_u *GoogleAuthUpdateOne) SetCredentials(v schema.Credentials) *GoogleAuthUpdateOne {
_u.mutation.SetCredentials(v)
return _u
}
// SetNillableCredentials sets the "credentials" field if the given value is not nil.
func (_u *GoogleAuthUpdateOne) SetNillableCredentials(v *google.Credentials) *GoogleAuthUpdateOne {
func (_u *GoogleAuthUpdateOne) SetNillableCredentials(v *schema.Credentials) *GoogleAuthUpdateOne {
if v != nil {
_u.SetCredentials(*v)
}
+7 -7
View File
@@ -7,8 +7,8 @@ import (
"errors"
"ersteller-lib/starter/ent/googleauth"
"ersteller-lib/starter/ent/predicate"
"ersteller-lib/starter/ent/schema"
"ersteller-lib/starter/ent/user"
"ersteller-lib/starter/google"
"fmt"
"sync"
"time"
@@ -38,7 +38,7 @@ type GoogleAuthMutation struct {
id *int
created_at *time.Time
updated_at *time.Time
credentials *google.Credentials
credentials *schema.Credentials
clearedFields map[string]struct{}
user *int
cleareduser bool
@@ -218,12 +218,12 @@ func (m *GoogleAuthMutation) ResetUpdatedAt() {
}
// SetCredentials sets the "credentials" field.
func (m *GoogleAuthMutation) SetCredentials(_go google.Credentials) {
m.credentials = &_go
func (m *GoogleAuthMutation) SetCredentials(s schema.Credentials) {
m.credentials = &s
}
// Credentials returns the value of the "credentials" field in the mutation.
func (m *GoogleAuthMutation) Credentials() (r google.Credentials, exists bool) {
func (m *GoogleAuthMutation) Credentials() (r schema.Credentials, exists bool) {
v := m.credentials
if v == nil {
return
@@ -234,7 +234,7 @@ func (m *GoogleAuthMutation) Credentials() (r google.Credentials, exists bool) {
// OldCredentials returns the old "credentials" field's value of the GoogleAuth entity.
// If the GoogleAuth object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *GoogleAuthMutation) OldCredentials(ctx context.Context) (v google.Credentials, err error) {
func (m *GoogleAuthMutation) OldCredentials(ctx context.Context) (v schema.Credentials, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldCredentials is only allowed on UpdateOne operations")
}
@@ -389,7 +389,7 @@ func (m *GoogleAuthMutation) SetField(name string, value ent.Value) error {
m.SetUpdatedAt(v)
return nil
case googleauth.FieldCredentials:
v, ok := value.(google.Credentials)
v, ok := value.(schema.Credentials)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
@@ -1,4 +1,4 @@
package google
package schema
import "golang.org/x/oauth2"
+1 -2
View File
@@ -2,7 +2,6 @@ package schema
import (
ersteller_ent "ersteller-lib/schema/ent"
google "ersteller-lib/starter/google"
"entgo.io/ent"
"entgo.io/ent/schema/edge"
@@ -21,7 +20,7 @@ func (GoogleAuth) Mixin() []ent.Mixin {
func (GoogleAuth) Fields() []ent.Field {
return []ent.Field{
field.JSON("credentials", google.Credentials{}),
field.JSON("credentials", Credentials{}),
}
}
+4 -2
View File
@@ -133,8 +133,10 @@ func GenerateEnvFile(rootPath string, overwrite bool) error {
// Define default values and comments for specific keys
defaults := map[string]string{
EnvKeyIsLocal: "true",
EnvKeyIsDev: "true",
EnvKeyDatabaseURL: "\"db/starter.db?_fk=1\"",
EnvKeyBaseURL: "\"http://localhost:8090\"",
EnvKeyIsLocal: "true",
EnvKeyIsDev: "true",
}
comments := map[string]string{
+63
View File
@@ -0,0 +1,63 @@
package google
import (
"crypto/rand"
"encoding/base64"
. "ersteller-lib"
"ersteller-lib/starter/ent"
"ersteller-lib/starter/env"
"net/http"
"time"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
)
const oAuthStateCookieName = "oauthstate"
const GoogleLogin = "/login/google"
const GoogleLoginCallback = "/google/authenticated"
type GoogleAuth struct {
db *ent.Client
server *http.ServeMux
environment env.Environment
config oauth2.Config
}
func NewGoogleAuth(db *ent.Client, server *http.ServeMux, environment env.Environment) *GoogleAuth {
config := oauth2.Config{
ClientID: environment.GoogleClientId,
ClientSecret: environment.GoogleClientSecret,
Endpoint: google.Endpoint,
RedirectURL: environment.BaseUrl + GoogleLoginCallback,
Scopes: []string{},
}
return &GoogleAuth{db: db, server: server, environment: environment, config: config}
}
func (g *GoogleAuth) AddRoutes() {
g.server.HandleFunc("GET "+GoogleLogin, func(writer http.ResponseWriter, request *http.Request) {
state := g.generateStateOauthCookie(writer)
url := g.config.AuthCodeURL(state, oauth2.AccessTypeOffline, oauth2.ApprovalForce)
http.Redirect(writer, request, url, http.StatusTemporaryRedirect)
})
}
func (g *GoogleAuth) generateStateOauthCookie(w http.ResponseWriter) string {
b := make([]byte, 16)
_, err := rand.Read(b)
if err != nil {
LogError("Failed to read random state: %v", err)
}
state := base64.URLEncoding.EncodeToString(b)
var expiration = time.Now().Add(time.Hour)
cookie := http.Cookie{Name: oAuthStateCookieName, Value: state, Expires: expiration, HttpOnly: true, Path: "/", Secure: false}
if g.environment.IsLocal {
cookie.SameSite = http.SameSiteLaxMode
cookie.Secure = false
}
http.SetCookie(w, &cookie)
return state
}
+19
View File
@@ -1,11 +1,14 @@
package main
import (
"context"
. "ersteller-lib"
"ersteller-lib/starter/ent"
"ersteller-lib/starter/env"
"ersteller-lib/starter/routes"
"log"
"net/http"
"time"
)
func main() {
@@ -13,6 +16,22 @@ func main() {
environment := env.LoadEnvironment()
Debug(environment)
client, err := ent.Open("sqlite3", environment.DatabaseUrl,
ent.Log(log.Println), ent.Debug())
if err != nil {
log.Fatalf("failed opening connection to sqlite: %v", err)
}
log.Println("client", client)
defer client.Close()
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*5)
defer cancel()
if err := client.Schema.Create(ctx); err != nil {
log.Fatalf("failed creating schema resources: %v", err)
}
Debug("starting white label app on port 8090")
handler := routes.CreateApi()
log.Fatal(http.ListenAndServe(":8090", handler))