func decodeResetPayload(ctx *app.Context, payload string) (reflect.Value, error) { se, err := ctx.App().EncryptSigner(Salt) if err != nil { return reflect.Value{}, err } value, err := se.UnsignDecrypt(payload) if err != nil { return reflect.Value{}, err } qs, err := url.ParseQuery(string(value)) if err != nil { return reflect.Value{}, err } userId, err := strconv.ParseInt(qs.Get("u"), 36, 64) if err != nil { return reflect.Value{}, err } ts, err := strconv.ParseInt(qs.Get("t"), 36, 64) if err != nil { return reflect.Value{}, err } if time.Since(time.Unix(ts, 0)) > PasswordResetExpiry { return reflect.Value{}, errResetExpired } user, userVal := newEmptyUser(ctx) ok := ctx.Orm().MustOne(orm.Eq("User.UserId", userId), userVal) if !ok { return reflect.Value{}, errNoSuchUser } return user, nil }
func validateNewUsername(ctx *app.Context, username string) error { userType := getUserType(ctx) found, err := ctx.Orm().Exists(ctx.Orm().TypeTable(userType), ByUsername(username)) if err != nil { return err } if found { return i18n.Errorf("username %q is already in use", username) } return nil }
func listUsers(ctx *app.Context) { userVal, ptr := newEmptyUser(ctx) iter := ctx.Orm().All().Iter() w := tabwriter.NewWriter(os.Stdout, 0, 8, 2, '\t', tabwriter.Debug) fmt.Fprint(w, "ID\tUsername\tEmail\tAdmin?\n") for iter.Next(ptr) { val := userVal.Elem().FieldByName("User").Interface().(User) fmt.Fprintf(w, "%d\t%s\t%s\t%v\n", val.UserId, val.Username, val.Email, val.Admin) } if err := w.Flush(); err != nil { panic(err) } }
func validateNewEmail(ctx *app.Context, email string) (string, error) { addr, err := mail.Validate(email, true) if err != nil { return "", i18n.Errorf("this does not look like a valid email address") } userType := getUserType(ctx) found, err := ctx.Orm().Exists(ctx.Orm().TypeTable(userType), ByEmail(addr)) if err != nil { return "", err } if found { return "", i18n.Errorf("email %q is already in use", addr) } return addr, nil }
func Get(ctx *app.Context, id int64) (app.User, error) { _, userVal := newEmptyUser(ctx) key := "gnd:la:user:"******"User.UserId", id), userVal) if err != nil { return nil, err } if !ok { return nil, errNoSuchUser } ctx.Cache().Set(key, userVal, 300) return userVal.(app.User), nil }
func ResetHandler(ctx *app.Context) { d := data(ctx) if !d.allowDirectSignIn() { ctx.NotFound("") return } payload := ctx.FormValue("p") var valid bool var expired bool var f *form.Form var user reflect.Value var err error var done bool if payload != "" { user, err = decodeResetPayload(ctx, payload) if err == nil && user.IsValid() { valid = true } else { if err == errResetExpired { expired = true } } } if valid { passwordForm := &PasswordForm{User: user} f = form.New(ctx, passwordForm) if f.Submitted() && f.IsValid() { ctx.Orm().MustSave(user.Interface()) ctx.MustSignIn(asGondolaUser(user)) done = true } } data := map[string]interface{}{ "Valid": valid, "Expired": expired, "Done": done, "User": user, "PasswordForm": f, "Payload": payload, } ctx.MustExecute(ResetTemplateName, data) }
func getByUsernameOrEmail(ctx *app.Context, usernameOrEmail string) (interface{}, error) { norm := Normalize(usernameOrEmail) _, userVal := newEmptyUser(ctx) var ok bool o := ctx.Orm() q1 := orm.Eq("User.NormalizedUsername", norm) q2 := orm.Eq("User.NormalizedEmail", norm) if o.Driver().Capabilities()&driver.CAP_OR != 0 { ok = o.MustOne(orm.Or(q1, q2), userVal) } else { ok = o.MustOne(q1, userVal) if !ok { ok = o.MustOne(q2, userVal) } } if !ok { return nil, ErrNoUser } return userVal, nil }
// Create creates a new user user with the given parameters, previously checking that // the given username and email aren't already in use. Note that the user is only created, // no implicit sign in is performed. func Create(ctx *app.Context, username string, email string, pw string) (app.User, error) { if err := validateNewUsername(ctx, username); err != nil { return nil, err } addr, err := validateNewEmail(ctx, email) if err != nil { return nil, err } user, userIface := newEmptyUser(ctx) setUserValue(user, "Username", username) setUserValue(user, "NormalizedUsername", Normalize(username)) setUserValue(user, "Email", addr) setUserValue(user, "NormalizedEmail", Normalize(addr)) setUserValue(user, "Password", password.New(pw)) setUserValue(user, "Created", time.Now().UTC()) if _, err = ctx.Orm().Insert(userIface); err != nil { return nil, err } return userIface.(app.User), nil }
func registerUser(ctx *app.Context) { username := ctx.RequireIndexValue(0) userVal, _ := newEmptyUser(ctx) updating := false if ctx.Orm().MustOne(ByUsername(username), userVal.Interface()) { // Updating existing user updating = true } else { // Creating a new one userVal = newUser(ctx, username) } var askPassword bool ctx.ParseParamValue("p", &askPassword) if !updating || askPassword { password1, err := speakeasy.Ask("Password:"******"Confirm Password:"******"passwords don't match")) } setUserValue(userVal, "Password", password.New(password1)) } var admin bool ctx.ParseParamValue("s", &admin) setUserValue(userVal, "Admin", admin) var email string ctx.ParseParamValue("e", &email) if email != "" { setUserValue(userVal, "Email", email) } ctx.Orm().MustSave(userVal.Interface()) ctx.Logger().Infof("saved user as %+v", userVal.Interface()) }
func FindFreeUsername(ctx *app.Context, username string) string { userType := getUserType(ctx) original := username ii := 1 o := ctx.Orm() tbl := o.TypeTable(userType) if tbl == nil { panic(fmt.Errorf("user type %s is not registered with the orm - add orm.Register(&%s{}) somewhere in your app", userType, userType.Name())) } for { exists, err := o.Exists(tbl, orm.Eq("User.NormalizedUsername", Normalize(username))) if err != nil { panic(err) } if !exists { break } username = original + strconv.Itoa(ii) ii++ } return username }
func userWithSocialAccount(ctx *app.Context, name SocialAccountType, acc socialAccount) (reflect.Value, error) { user, userVal := newEmptyUser(ctx) ok, err := ctx.Orm().One(orm.Eq(name.String()+".Id", acc.accountId()), userVal) if err != nil { return reflect.Value{}, err } acVal := reflect.Indirect(reflect.ValueOf(acc)) imageVal := acVal.FieldByName("Image") imageFormatVal := acVal.FieldByName("ImageFormat") imageURLVal := acVal.FieldByName("ImageURL") if ok { prev := getUserValue(user, name.String()) if prev != nil { prevVal := reflect.Indirect(reflect.ValueOf(prev)) prevImage := prevVal.FieldByName("Image").String() prevImageFormat := prevVal.FieldByName("ImageFormat").String() prevImageURL := prevVal.FieldByName("ImageURL").String() image, imageFormat, imageURL := mightFetchImage(ctx, acc.imageURL(), prevImage, prevImageFormat, prevImageURL) imageVal.Set(reflect.ValueOf(image)) imageFormatVal.Set(reflect.ValueOf(imageFormat)) imageURLVal.Set(reflect.ValueOf(imageURL)) } // Note: don't update main email, since it could // cause a conflict if the new email is already in the db. // already registered wi setUserValue(user, name.String(), acc) } else { image, imageFormat, imageURL := fetchImage(ctx, acc.imageURL()) imageVal.Set(reflect.ValueOf(image)) imageFormatVal.Set(reflect.ValueOf(imageFormat)) imageURLVal.Set(reflect.ValueOf(imageURL)) // Check email if email := acc.email(); email != "" { // Check if we have a user with that email. In that case // Add this social account to his account. ok, err = ctx.Orm().One(orm.Eq("User.NormalizedEmail", Normalize(email)), userVal) if err != nil { return reflect.Value{}, err } if ok { setUserValue(user, name.String(), acc) } } if !ok { // This is a bit racy, but we'll live with it for now username := acc.username() freeUsername := FindFreeUsername(ctx, username) user = newUser(ctx, freeUsername) setUserValue(user, "AutomaticUsername", true) setUserValue(user, "Email", acc.email()) setUserValue(user, name.String(), acc) } } ctx.Orm().MustSave(user.Interface()) return user, nil }
func saveNewUser(ctx *app.Context, user reflect.Value) { setUserValue(user, "Password", password.New(string(getUserValue(user, "Password").(password.Password)))) setUserValue(user, "Created", time.Now().UTC()) ctx.Orm().MustInsert(user.Interface()) ctx.MustSignIn(asGondolaUser(user)) }