Example #1
0
// Fetch the claims of a user.
func fetchClaims(d *sql.DB, user User) (User, *utils.GoAuthError) {
	rows, err := d.Query("SELECT uc.value, c.name, c.required FROM user_claim AS uc INNER JOIN claim AS c ON c.name=uc.claim WHERE uc.user=?", user.id)
	if err != nil {
		log.Println(err)
		customErr := utils.NewGoAuthError(500, "Could not execute the query")
		return User{}, &customErr
	}

	defer rows.Close()
	user.claims = make(map[Claim]UserClaim)
	claim := Claim{}
	var value UserClaim
	for rows.Next() {
		err := rows.Scan(&value, &claim.name, &claim.required)
		if err != nil {
			log.Println(err)
			customErr := utils.NewGoAuthError(500, "Could not parse the claim")
			return User{}, &customErr
		}
		user.claims[claim] = value
	}

	err = rows.Err()
	if err != nil {
		log.Println(err)
		customErr := utils.NewGoAuthError(500, "Could not could not parse all claims")
		return User{}, &customErr
	}

	return user, nil
}
Example #2
0
// Store a new user in the repository. Validates if the given email looks like
// an email and is not yet taken by somebody. If these conditions have been
// met then the new user will be stored and a verification email will be sent
// to the new user.
func (s UserService) Register(email, password string) (User, *utils.GoAuthError) {
	emptyUser := User{}
	if !utils.ValidateEmail(email) {
		customErr := utils.NewGoAuthError(400, "Invalid email adres")
		return emptyUser, &customErr
	}

	user, err := s.repository.findByEmail(email)
	// Email was not yet taken.
	if err.Status == 404 {
		user = NewUser(email, password)

		// Validate if the ID is already taken or not.
		taken, err := s.repository.isTakenID(user.id)
		for taken {
			user.generateNewID()
			taken, err = s.repository.isTakenID(user.id)
			if err != nil {
				return emptyUser, err
			}
		}

		// Validate if the verification token is already taken
		taken, err = s.repository.isTakenToken(user.email.token)
		for taken {
			user.email.GenerateNewToken()
			taken, err = s.repository.isTakenToken(user.email.token)
			if err != nil {
				return emptyUser, err
			}
		}

		err = s.repository.saveUser(user)
		if err != nil {
			return emptyUser, err
		}

		// @TODO: send an verification email to the new user.

		return user, nil
	}

	// Some other error occured.
	if err != nil {
		return emptyUser, err
	}

	// User was found without any errors. Email is already taken.
	customErr := utils.NewGoAuthError(409, "Email is already taken")
	return emptyUser, &customErr
}
Example #3
0
func validate(token string) (map[string]interface{}, *utils.GoAuthError) {
	split := strings.Split(token, " ")
	if len(split) != 2 {
		customErr := utils.NewGoAuthError(401, "Unauthorized")
		return nil, &customErr
	}

	decoded, err := gose.DecodePayloadWhenValid(split[1], core.Configuration.JWTSecret)
	if err != nil {
		customErr := utils.NewGoAuthError(401, "Unauthorized")
		return nil, &customErr
	}

	return decoded, nil
}
Example #4
0
// Allow to change the password, if the `old` arg matches the current
// password.
func (u *User) SetPassword(old, new string) *utils.GoAuthError {
	if u.password.Validate(old) {
		u.setPassword(new)
		return nil
	}

	goAutErr := utils.NewGoAuthError(400, "Wrong password")
	return &goAutErr
}
Example #5
0
// Store the given user in the database. This is done by several "upsert"
// commands. All of them have to succeed.
func (r UserRepository) saveUser(user User) *utils.GoAuthError {
	tx, err := r.database.Begin()
	if err != nil {
		log.Println(err)
		customErr := utils.NewGoAuthError(500, "Could not start a transaction")
		return &customErr
	}

	_, userInsertErr := r.database.Exec("INSERT OR IGNORE INTO user (id) VALUES (?)", user.id)
	_, passwordInsertErr := r.database.Exec("INSERT OR IGNORE INTO password (user, hash, salt) VALUES (?, ?, ?)", user.id, user.password.hash, user.password.salt)
	_, passwordUpdateErr := r.database.Exec("UPDATE password SET hash=?, salt=? WHERE user=?", user.password.hash, user.password.salt, user.id)
	_, emailInsertErr := r.database.Exec("INSERT OR IGNORE INTO email (user, email, token, verified) VALUES (?, ?, ?, ?)", user.id, user.email.email, user.email.token, user.email.verified)
	_, emailUpdateErr := r.database.Exec("UPDATE email SET email=?, token=?, verified=? WHERE user=?", user.email.email, user.email.token, user.email.verified, user.id)

	if !utils.AreNil(userInsertErr, passwordInsertErr, passwordUpdateErr, emailInsertErr, emailUpdateErr) {
		log.Println(userInsertErr, passwordInsertErr, passwordUpdateErr, emailInsertErr, emailUpdateErr)
		tx.Rollback()
		customErr := utils.NewGoAuthError(500, "Could not upsert the given user")
		return &customErr
	}

	for k, v := range user.claims {
		_, userClaimInsertErr := r.database.Exec("INSERT OR IGNORE INTO user_claim (user, claim, value) VALUES (?, ?, ?)", user.id, k.name, v)
		_, userClaimUpdateErr := r.database.Exec("UPDATE user_claim SET value=? WHERE user=? AND claim=?", v, user.id, k.name)

		if !utils.AreNil(userClaimInsertErr, userClaimUpdateErr) {
			log.Println(userClaimInsertErr, userClaimUpdateErr)
			tx.Rollback()
			customErr := utils.NewGoAuthError(500, "Could not upsert the user's claims")
			return &customErr
		}
	}

	err = tx.Commit()
	if err != nil {
		log.Println(err)
		customErr := utils.NewGoAuthError(500, "Could not conclude the transaction")
		return &customErr
	}

	return nil
}
Example #6
0
// Handles the logic for the user login. Find a user and validate if the
// password matches the stored password.
func (s UserService) LogIn(email, password string) (User, *utils.GoAuthError) {
	user, err := s.repository.findByEmail(email)
	if err != nil {
		return User{}, err
	}

	if user.password.Validate(password) {
		return user, nil
	}

	customErr := utils.NewGoAuthError(400, "Wrong email/password combo")
	return User{}, &customErr
}
Example #7
0
// Check if the given token already is taken by another user.
func (r UserRepository) isTakenToken(token string) (bool, *utils.GoAuthError) {
	row := r.database.QueryRow("SELECT email FROM email WHERE token=?", token)
	email := Email{}

	err := row.Scan(&email.email)
	if err != nil && err.Error() != "sql: no rows in result set" {
		log.Println(err)
		customErr := utils.NewGoAuthError(500, "Could not execute the query")
		return false, &customErr
	}

	// No results would mean err is not nil, ergo when the token is not yet
	// taken err is not nil.
	return err == nil, nil
}
Example #8
0
// Check if there already is a user bound to the given ID.
func (r UserRepository) isTakenID(id string) (bool, *utils.GoAuthError) {
	row := r.database.QueryRow("SELECT * FROM user WHERE id=?", id)
	user := User{}

	err := row.Scan(&user.id)
	if err != nil && err.Error() != "sql: no rows in result set" {
		log.Println(err)
		customErr := utils.NewGoAuthError(500, "Could not execute the query")
		return false, &customErr
	}

	// No results would mean err is not nil, ergo when the ID is not yet taken
	// err is not nil.
	return err == nil, nil
}
Example #9
0
// A helper function to parse a row as a user.
func parseUserRow(row *sql.Row) (User, *utils.GoAuthError) {
	user := User{}
	email := Email{}
	password := Password{}

	err := row.Scan(&user.id, &email.email, &email.verified, &email.token, &password.hash, &password.salt)
	if err != nil {
		log.Println(err)
		customErr := utils.NewGoAuthError(404, "Could not find that user")
		return User{}, &customErr
	}

	user.email = email
	user.password = password

	return user, nil
}