|
| 1 | +package auth |
| 2 | + |
| 3 | +import ( |
| 4 | + "database/sql" |
| 5 | + "encoding/json" |
| 6 | + "errors" |
| 7 | + "strings" |
| 8 | + |
| 9 | + "github.com/gistapp/api/user" |
| 10 | + "github.com/gistapp/api/utils" |
| 11 | + "github.com/gofiber/fiber/v2" |
| 12 | + "github.com/gofiber/fiber/v2/log" |
| 13 | + "github.com/markbates/goth" |
| 14 | + "github.com/markbates/goth/providers/github" |
| 15 | + "github.com/markbates/goth/providers/google" |
| 16 | + "github.com/shareed2k/goth_fiber" |
| 17 | +) |
| 18 | + |
| 19 | +type AuthServiceImpl struct{} |
| 20 | + |
| 21 | +func (a *AuthServiceImpl) Authenticate(c *fiber.Ctx) error { |
| 22 | + if user, err := goth_fiber.CompleteUserAuth(c); err == nil { |
| 23 | + log.Info(user) |
| 24 | + return nil |
| 25 | + } else { |
| 26 | + return goth_fiber.BeginAuthHandler(c) |
| 27 | + } |
| 28 | +} |
| 29 | + |
| 30 | +// generates a token and sends it to the user by email |
| 31 | +func (a *AuthServiceImpl) LocalAuth(email string) error { |
| 32 | + token_val := utils.GenToken(6) |
| 33 | + token_model := TokenSQL{ |
| 34 | + Keyword: sql.NullString{String: email, Valid: true}, |
| 35 | + Value: sql.NullString{String: token_val, Valid: true}, |
| 36 | + Type: sql.NullString{String: string(LocalAuth), Valid: true}, |
| 37 | + } |
| 38 | + |
| 39 | + _, err := token_model.Save() |
| 40 | + |
| 41 | + if err != nil { |
| 42 | + return err |
| 43 | + } |
| 44 | + |
| 45 | + err = utils.SendEmail("Gistapp: Local Auth", "Your token is: "+token_val, email) |
| 46 | + |
| 47 | + return err |
| 48 | +} |
| 49 | + |
| 50 | +// verifies the token and finishes the registration |
| 51 | +func (a *AuthServiceImpl) VerifyLocalAuthToken(token string, email string) (string, error) { |
| 52 | + token_model := TokenSQL{ |
| 53 | + Value: sql.NullString{String: token, Valid: true}, |
| 54 | + Keyword: sql.NullString{String: email, Valid: true}, |
| 55 | + Type: sql.NullString{String: string(LocalAuth), Valid: true}, |
| 56 | + } |
| 57 | + token_data, err := token_model.Get() |
| 58 | + if err != nil { |
| 59 | + return "", err |
| 60 | + } |
| 61 | + err = token_data.Delete() |
| 62 | + if err != nil { |
| 63 | + return "", errors.New("couldn't invalidate token") |
| 64 | + } |
| 65 | + |
| 66 | + //now we finish users registration |
| 67 | + goth_user := goth.User{ |
| 68 | + UserID: email, |
| 69 | + Name: strings.Split(email, "@")[0], |
| 70 | + Email: email, |
| 71 | + AvatarURL: "https://vercel.com/api/www/avatar/?u=" + email + "&s=80", |
| 72 | + } |
| 73 | + |
| 74 | + if user, _, err := a.GetUser(goth_user); err == nil { |
| 75 | + jwt_token, err := utils.CreateToken(user.Email, user.ID) |
| 76 | + if err != nil { |
| 77 | + return "", err |
| 78 | + } |
| 79 | + return jwt_token, nil |
| 80 | + } |
| 81 | + |
| 82 | + user, err := a.Register(goth_user) |
| 83 | + |
| 84 | + if err != nil { |
| 85 | + return "", err |
| 86 | + } |
| 87 | + |
| 88 | + jwt_token, err := utils.CreateToken(user.Email, user.ID) |
| 89 | + |
| 90 | + return jwt_token, err |
| 91 | +} |
| 92 | + |
| 93 | +func (a *AuthServiceImpl) Callback(c *fiber.Ctx) error { |
| 94 | + auth_user, err := goth_fiber.CompleteUserAuth(c) |
| 95 | + if err != nil { |
| 96 | + log.Error(err) |
| 97 | + return ErrCantCompleteAuth |
| 98 | + } |
| 99 | + |
| 100 | + user_md, _, err := a.GetUser(auth_user) |
| 101 | + |
| 102 | + if err == nil { |
| 103 | + token, err := utils.CreateToken(user_md.Email, user_md.ID) |
| 104 | + if err != nil { |
| 105 | + return err |
| 106 | + } |
| 107 | + return c.JSON(fiber.Map{ |
| 108 | + "token": token, |
| 109 | + }) |
| 110 | + } |
| 111 | + |
| 112 | + user_md, err = a.Register(auth_user) |
| 113 | + |
| 114 | + if err != nil { |
| 115 | + return err |
| 116 | + } |
| 117 | + |
| 118 | + jwt, err := utils.CreateToken(user_md.Email, user_md.ID) |
| 119 | + if err != nil { |
| 120 | + return err |
| 121 | + } |
| 122 | + |
| 123 | + return c.JSON(fiber.Map{ |
| 124 | + "token": jwt, |
| 125 | + }) |
| 126 | +} |
| 127 | + |
| 128 | +func (a *AuthServiceImpl) GetUser(auth_user goth.User) (*user.User, *AuthIdentity, error) { |
| 129 | + auth_and_user, err := new(AuthIdentitySQL).GetWithUser(auth_user.UserID) |
| 130 | + if err != nil { |
| 131 | + return nil, nil, err |
| 132 | + } |
| 133 | + |
| 134 | + return &auth_and_user.User, &auth_and_user.AuthIdentity, nil |
| 135 | +} |
| 136 | + |
| 137 | +func (a *AuthServiceImpl) Register(auth_user goth.User) (*user.User, error) { |
| 138 | + data, err := json.Marshal(auth_user) |
| 139 | + if err != nil { |
| 140 | + return nil, errors.New("couldn't marshal user") |
| 141 | + } |
| 142 | + |
| 143 | + user_model := user.UserSQL{ |
| 144 | + ID: sql.NullString{String: auth_user.UserID, Valid: true}, |
| 145 | + Email: sql.NullString{String: auth_user.Email, Valid: true}, |
| 146 | + Name: sql.NullString{String: auth_user.Name, Valid: true}, |
| 147 | + Picture: sql.NullString{String: auth_user.AvatarURL, Valid: true}, |
| 148 | + } |
| 149 | + |
| 150 | + user_data, err := user_model.Save() |
| 151 | + |
| 152 | + if err != nil { |
| 153 | + return nil, err |
| 154 | + } |
| 155 | + |
| 156 | + auth_identity_model := AuthIdentitySQL{ |
| 157 | + Data: sql.NullString{String: string(data), Valid: true}, |
| 158 | + Type: sql.NullString{String: auth_user.Provider, Valid: true}, |
| 159 | + OwnerID: sql.NullString{String: user_data.ID, Valid: true}, |
| 160 | + ProviderID: sql.NullString{String: auth_user.UserID, Valid: true}, |
| 161 | + } |
| 162 | + |
| 163 | + auth_identity, err := auth_identity_model.Save() |
| 164 | + log.Info(auth_identity) |
| 165 | + return user_data, err |
| 166 | +} |
| 167 | + |
| 168 | +func (a *AuthServiceImpl) RegisterProviders() { |
| 169 | + goth.UseProviders( |
| 170 | + google.New(utils.Get("GOOGLE_KEY"), utils.Get("GOOGLE_SECRET"), utils.Get("PUBLIC_URL")+"/auth/callback/google"), |
| 171 | + github.New(utils.Get("GITHUB_KEY"), utils.Get("GITHUB_SECRET"), utils.Get("PUBLIC_URL")+"/auth/callback/github"), |
| 172 | + ) |
| 173 | +} |
| 174 | + |
| 175 | +func (a *AuthServiceImpl) IsAuthenticated(token string) (*JWTClaim, error) { |
| 176 | + claims, err := utils.VerifyJWT(token) |
| 177 | + |
| 178 | + if err != nil { |
| 179 | + return nil, err |
| 180 | + } |
| 181 | + |
| 182 | + jwtClaim := new(JWTClaim) |
| 183 | + jwtClaim.Pub = claims["pub"].(string) |
| 184 | + jwtClaim.Email = claims["email"].(string) |
| 185 | + |
| 186 | + return jwtClaim, nil |
| 187 | +} |
| 188 | + |
| 189 | +var AuthService AuthServiceImpl = AuthServiceImpl{} |
| 190 | +var ErrCantCompleteAuth = errors.New("can't complete auth") |
0 commit comments