예제 #1
1
func (h *Handler) handleVerify(w http.ResponseWriter, r *http.Request) {
	segments := strings.Split(strings.Trim(r.URL.Path, "/"), "/")
	vid := segments[2]

	u, err := user.Verify(vid)
	if err != nil {
		logger.Error(w, err)
		h.serveServerError(w, r)
		return
	}

	s, err := session.New(u)
	if err != nil {
		logger.Error(w, err)
		h.serveServerError(w, r)
		return
	}

	// Drop cookie
	err = s.Save(w, true)
	if err != nil {
		logger.Error(w, err)
		h.serveServerError(w, r)
		return
	}

	url := fmt.Sprintf("%s/u/%s", config.Get("baseurl"), u.Username)
	http.Redirect(w, r, url, http.StatusFound)
}
예제 #2
0
func (h *Handler) handleUserPassword(w http.ResponseWriter, r *http.Request) {
	segments := strings.Split(strings.Trim(r.URL.Path, "/"), "/")
	username := segments[2]

	s, err := session.Parse(r)
	if err != nil {
		http.Redirect(w, r, fmt.Sprintf("%s/u/%s",
			config.Get("baseurl"), username), http.StatusFound)
		return
	}

	if s.User.Username != username {
		http.Redirect(w, r, fmt.Sprintf("%s/u/%s",
			config.Get("baseurl"), username), http.StatusFound)
		return
	}

	msg, _ := flashdata.Get(w, r)

	m := map[string]interface{}{
		"baseurl": config.Get("baseurl"),
		"session": s,
		"message": msg,
	}

	h.Templates.ExecuteTemplate(w, "user_update_password.html", m)
}
예제 #3
0
func (h *Handler) handleClientNew(w http.ResponseWriter, r *http.Request) {
	segments := strings.Split(strings.Trim(r.URL.Path, "/"), "/")
	username := segments[2]

	s, err := session.Parse(r)
	if err != nil {
		http.Redirect(w, r, fmt.Sprintf("%s/u/%s",
			config.Get("baseurl"), username), http.StatusFound)
		return
	}

	if s.User.Username != username {
		http.Redirect(w, r, fmt.Sprintf("%s/u/%s",
			config.Get("baseurl"), username), http.StatusFound)
		return
	}

	m := map[string]interface{}{
		"baseurl": config.Get("baseurl"),
		"session": s,
		"form": map[string]string{
			"email":    s.User.Email,
			"fullname": s.User.Fullname,
		},
	}

	h.Templates.ExecuteTemplate(w, "user_new_client.html", m)
}
예제 #4
0
func allowed() bool {
	if check {
		ok := strings.ToLower(config.Get("logging"))
		allow = (ok == "true" || ok == "on" || ok == "1")
		header = config.Get("response_header")
		check = false
	}
	return allow
}
예제 #5
0
func (h *Handler) handleNewPost(w http.ResponseWriter, r *http.Request) {
	username := strings.TrimSpace(r.FormValue("username"))
	email := strings.TrimSpace(r.FormValue("email"))
	password := strings.TrimSpace(r.FormValue("password"))

	// Validate
	v := validation.New()
	if v.Required("username", username, "username is required") {
		v.Username("username", username, "invalid username")
	}
	if v.Required("email", email, "email is required") {
		v.Email("email", email, "invalid email")
	}
	v.Required("password", password, "password is required")

	if len(v.Errors) == 0 {
		err := user.Add(username, email, password)
		if err == nil {
			msg := `
                Account created.
                Please check your email for your verification link
            `

			flashdata.Set(w, msg)

			url := fmt.Sprintf("%s/message", config.Get("baseurl"))
			http.Redirect(w, r, url, http.StatusFound)

			return
		} else {
			if err.Error() == "UNIQUE constraint failed: user.username" {
				v.Errors["username"] = "******"
			} else if err.Error() == "UNIQUE constraint failed: user.email" {
				v.Errors["email"] = "email already exists"
			} else {
				logger.Error(w, err)
				h.serveServerError(w, r)
				return
			}
		}
	}

	m := map[string]interface{}{
		"baseurl": config.Get("baseurl"),
		"form": map[string]string{
			"username": username,
			"email":    email,
		},
		"errors": v.Errors,
	}

	h.Templates.ExecuteTemplate(w, "new.html", m)
}
예제 #6
0
func (h *Handler) handleUserUpdatePost(w http.ResponseWriter, r *http.Request) {
	segments := strings.Split(strings.Trim(r.URL.Path, "/"), "/")
	username := segments[2]

	s, err := session.Parse(r)
	if err != nil {
		http.Redirect(w, r, fmt.Sprintf("%s/u/%s",
			config.Get("baseurl"), username), http.StatusFound)
		return
	}

	if s.User.Username != username {
		http.Redirect(w, r, fmt.Sprintf("%s/u/%s",
			config.Get("baseurl"), username), http.StatusFound)
		return
	}

	email := strings.TrimSpace(r.FormValue("email"))
	fullname := strings.TrimSpace(r.FormValue("fullname"))

	// Validate
	v := validation.New()
	if v.Required("email", email, "email is required") {
		v.Email("email", email, "invalid email")
	}

	if len(v.Errors) == 0 {
		err = s.User.Update(email, fullname)
		if err != nil {
			logger.Error(w, err)
			h.serveServerError(w, r)
			return
		}
		flashdata.Set(w, "Profile updated")
		http.Redirect(w, r, fmt.Sprintf("%s/u/%s", config.Get("baseurl"),
			s.User.Username), http.StatusFound)
		return
	}

	m := map[string]interface{}{
		"baseurl": config.Get("baseurl"),
		"session": s,
		"form": map[string]string{
			"email":    email,
			"fullname": fullname,
		},
		"errors": v.Errors,
	}

	h.Templates.ExecuteTemplate(w, "user_update.html", m)
}
예제 #7
0
func loadTemplates() {
	if Templates == nil {
		t, _ := template.ParseGlob(
			filepath.Join(config.Get("email"), "*.*"))
		Templates = t
	}
}
예제 #8
0
func (h *Handler) handleLogout(w http.ResponseWriter, r *http.Request) {
	s, _ := session.Parse(r)
	if s != nil {
		s.Save(w, false)
	}
	http.Redirect(w, r, config.Get("baseurl"), http.StatusFound)
}
예제 #9
0
func (h *Handler) handleNew(w http.ResponseWriter, r *http.Request) {
	m := map[string]interface{}{
		"baseurl": config.Get("baseurl"),
	}

	h.Templates.ExecuteTemplate(w, "new.html", m)
}
예제 #10
0
func Row(q string, params []interface{}, bind []interface{}) error {
	db, err := sql.Open("sqlite3", config.Get("dbf"))
	if err != nil {
		return err
	}
	defer db.Close()

	stmt, err := db.Prepare(q)
	if err != nil {
		return err
	}
	defer stmt.Close()

	row := stmt.QueryRow(params...)
	if err != nil {
		return err
	}

	err = row.Scan(bind...)
	if err != nil {
		return err
	}

	return nil
}
예제 #11
0
func (s *Session) Save(w http.ResponseWriter, keepalive bool) error {
	q := `
        UPDATE user_session SET
            valid_until = ?
            , modified_date = ?
        WHERE id = ?;
    `

	valid := int64(0)

	if keepalive {
		valid = time.Now().Unix() + SESSION_OFFSET
	}

	params := []interface{}{
		valid,
		time.Now().Unix(),
		s.Id,
	}

	_, err := dao.Exec(q, params)
	if err != nil {
		return err
	}

	expires := -1

	if keepalive {
		expires, _ = strconv.Atoi(config.Get("session_cookie_expires"))
	}

	secure, _ := strconv.ParseBool(config.Get("session_cookie_secure"))

	c := new(http.Cookie)
	c.Name = config.Get("session_cookie_name")
	if keepalive {
		c.Value = s.Key
	}
	c.Path = config.Get("session_cookie_path")
	c.MaxAge = expires
	c.Secure = secure

	http.SetCookie(w, c)
	logger.Log(w, "SET-COOKIE", c.String())
	return nil
}
예제 #12
0
func Set(w http.ResponseWriter, s string) {
	secure, _ := strconv.ParseBool(config.Get("session_cookie_secure"))

	c := new(http.Cookie)
	c.Name = fmt.Sprintf("%s-flash", config.Get("session_cookie_name"))
	c.Path = config.Get("session_cookie_path")
	c.Value = base64.URLEncoding.EncodeToString([]byte(strings.TrimSpace(s)))
	if c.Value != "" {
		c.MaxAge = 0
	} else {
		c.MaxAge = -1
	}
	c.Secure = secure

	http.SetCookie(w, c)
	logger.Log(w, "SET-COOKIE", c.String())
}
예제 #13
0
func (h *Handler) handleMessage(w http.ResponseWriter, r *http.Request) {
	s, ok := flashdata.Get(w, r)
	if !ok {
		http.Redirect(w, r, config.Get("baseurl"), http.StatusFound)
		return
	}

	s = strings.Replace(s, "\n", "<br>\n", -1)
	logger.Info(w, s)

	m := map[string]interface{}{
		"baseurl": config.Get("baseurl"),
		"message": template.HTML(s),
	}

	h.Templates.ExecuteTemplate(w, "message.html", m)
}
예제 #14
0
func (h *Handler) handleLoginPost(w http.ResponseWriter, r *http.Request) {
	username := strings.TrimSpace(r.FormValue("username"))
	password := strings.TrimSpace(r.FormValue("password"))

	// Validate
	v := validation.New()
	v.Required("username", username, "username is required")
	v.Required("password", password, "password is required")

	if len(v.Errors) == 0 {
		u, err := user.Login(username, password)
		if err == nil {
			s, err := session.New(u)
			if err != nil {
				logger.Error(w, err)
				h.serveServerError(w, r)
				return
			}

			err = s.Save(w, true)
			if err != nil {
				logger.Error(w, err)
				h.serveServerError(w, r)
				return
			}

			url := fmt.Sprintf("%s/u/%s", config.Get("baseurl"), u.Username)
			http.Redirect(w, r, url, http.StatusFound)
			return
		} else {
			if err.Error() == "sql: no rows in result set" {
				v.Errors["username"] = "******"
			}
		}
	}

	m := map[string]interface{}{
		"baseurl": config.Get("baseurl"),
		"form": map[string]string{
			"username": username,
		},
		"errors": v.Errors,
	}

	h.Templates.ExecuteTemplate(w, "login.html", m)
}
예제 #15
0
func (h *Handler) serveServerError(w http.ResponseWriter, r *http.Request) {
	s, _ := session.Parse(r)
	m := map[string]interface{}{
		"baseurl": config.Get("baseurl"),
		"session": s,
	}
	w.WriteHeader(http.StatusInternalServerError)
	h.Templates.ExecuteTemplate(w, "error500.html", m)
}
예제 #16
0
func (h *Handler) handleUserPasswordPost(w http.ResponseWriter, r *http.Request) {
	segments := strings.Split(strings.Trim(r.URL.Path, "/"), "/")
	username := segments[2]

	s, err := session.Parse(r)
	if err != nil {
		http.Redirect(w, r, fmt.Sprintf("%s/u/%s",
			config.Get("baseurl"), username), http.StatusFound)
		return
	}

	if s.User.Username != username {
		http.Redirect(w, r, fmt.Sprintf("%s/u/%s",
			config.Get("baseurl"), username), http.StatusFound)
		return
	}

	password := strings.TrimSpace(r.FormValue("password"))

	// Validate
	v := validation.New()
	v.Required("password", password, "new password is required")

	if len(v.Errors) == 0 {
		err := s.User.UpdatePassword(password)
		if err != nil {
			logger.Error(w, err)
			h.serveServerError(w, r)
			return
		}
		flashdata.Set(w, "Password updated")
		http.Redirect(w, r, fmt.Sprintf("%s/u/%s",
			config.Get("baseurl"), s.User.Username), http.StatusFound)
		return
	}

	m := map[string]interface{}{
		"baseurl": config.Get("baseurl"),
		"session": s,
		"errors":  v.Errors,
	}

	h.Templates.ExecuteTemplate(w, "user_update_password.html", m)
}
예제 #17
0
func (h *Handler) loadTemplates() error {
	t, err := template.ParseGlob(filepath.Join(config.Get("templates"), "*.*"))
	if err != nil {
		return err
	}

	h.Templates = t

	return nil
}
예제 #18
0
func (h *Handler) handleForgotPost(w http.ResponseWriter, r *http.Request) {
	username := strings.TrimSpace(r.FormValue("username"))

	// Validate
	v := validation.New()
	v.Required("username", username, "username is required")

	if len(v.Errors) == 0 {
		u, err := user.Find(username)
		if err != nil {
			logger.Error(w, err)
			h.serveServerError(w, r)
			return
		}
		err = user.SendVerify(u.Id, u.Email, false)
		if err != nil {
			logger.Error(w, err)
			h.serveServerError(w, r)
			return
		}

		msg := `
            Password reset link sent
        `

		flashdata.Set(w, msg)

		url := fmt.Sprintf("%s/message", config.Get("baseurl"))
		http.Redirect(w, r, url, http.StatusFound)

		return
	}

	m := map[string]interface{}{
		"baseurl": config.Get("baseurl"),
		"form": map[string]string{
			"username": username,
		},
		"errors": v.Errors,
	}

	h.Templates.ExecuteTemplate(w, "forgot.html", m)
}
예제 #19
0
func (h *Handler) handleHome(w http.ResponseWriter, r *http.Request) {
	s, err := session.Parse(r)
	if err != nil {
		logger.Error(w, err)
	} else {
		err = s.Save(w, true)
		if err != nil {
			logger.Error(w, err)
		}
	}

	if s != nil {
		url := fmt.Sprintf("%s/u/%s", config.Get("baseurl"), s.User.Username)
		http.Redirect(w, r, url, http.StatusFound)
		return
	}

	m := map[string]interface{}{
		"baseurl": config.Get("baseurl"),
	}

	h.Templates.ExecuteTemplate(w, "home.html", m)
}
예제 #20
0
func Exec(q string, params []interface{}) (sql.Result, error) {
	db, err := sql.Open("sqlite3", config.Get("dbf"))
	if err != nil {
		return nil, err
	}
	defer db.Close()

	stmt, err := db.Prepare(q)
	if err != nil {
		return nil, err
	}
	defer stmt.Close()

	return stmt.Exec(params...)
}
예제 #21
0
func New() (*Handler, error) {
	h := new(Handler)

	h.header = config.Get("response_header")

	h.Rules = []*Rule{
		&Rule{"GET:/timesheet", nil, h.handleHome},
		&Rule{"GET:/timesheet/forgot", nil, h.handleForgot},
		&Rule{"GET:/timesheet/logout", nil, h.handleLogout},
		&Rule{"GET:/timesheet/message", nil, h.handleMessage},
		&Rule{"GET:/timesheet/new", nil, h.handleNew},
		&Rule{"GET:/timesheet/purge", nil, h.handlePurge},
		&Rule{"GET:/timesheet/u", nil, h.handleLogin},
		&Rule{fmt.Sprintf("GET:/timesheet/u/%s", user.USERNAME_PATTERN),
			nil, h.handleUser},
		&Rule{fmt.Sprintf("GET:/timesheet/u/%s/client/new",
			user.USERNAME_PATTERN), nil, h.handleClientNew},
		&Rule{fmt.Sprintf("GET:/timesheet/u/%s/password",
			user.USERNAME_PATTERN), nil, h.handleUserPassword},
		&Rule{fmt.Sprintf("GET:/timesheet/u/%s/update", user.USERNAME_PATTERN),
			nil, h.handleUserUpdate},
		&Rule{"GET:/timesheet/verify/[A-Fa-f0-9][A-Fa-f0-9-]*", nil, h.handleVerify},
		&Rule{"POST:/timesheet/forgot", nil, h.handleForgotPost},
		&Rule{"POST:/timesheet/new", nil, h.handleNewPost},
		&Rule{"POST:/timesheet/u", nil, h.handleLoginPost},
		&Rule{fmt.Sprintf("POST:/timesheet/u/%s/password", user.USERNAME_PATTERN),
			nil, h.handleUserPasswordPost},
		&Rule{fmt.Sprintf("POST:/timesheet/u/%s/update", user.USERNAME_PATTERN),
			nil, h.handleUserUpdatePost},
	}

	// Compile rules
	for _, rule := range h.Rules {
		re, err := regexp.Compile(fmt.Sprintf("^%s$",
			strings.TrimRight(rule.Pattern, "/")))
		if err != nil {
			panic(err)
		}
		rule.Compiled = re
	}

	err := h.loadTemplates()
	if err != nil {
		return nil, err
	}

	return h, nil
}
예제 #22
0
func Get(w http.ResponseWriter, r *http.Request) (string, bool) {
	c, err := r.Cookie(fmt.Sprintf("%s-flash",
		config.Get("session_cookie_name")))
	if err != nil {
		return "", false
	}

	b, err := base64.URLEncoding.DecodeString(c.Value)
	if err != nil {
		return "", false
	}

	Set(w, "")

	return string(b), true
}
예제 #23
0
func Parse(r *http.Request) (*Session, error) {
	c, err := r.Cookie(config.Get("session_cookie_name"))
	if err != nil {
		return nil, err
	}

	q := `
        SELECT
            s.id
            , u.key
        FROM user u, user_session s
        WHERE u.id = s.user_id
        AND u.active = 1
        AND s.key = ?
        AND s.valid_until > ?;
    `

	params := []interface{}{
		c.Value,
		time.Now().Unix(),
	}

	var sid int64
	var ukey string

	bind := []interface{}{
		&sid,
		&ukey,
	}

	err = dao.Row(q, params, bind)
	if err != nil {
		return nil, err
	}

	u, err := user.Load(ukey)
	if err != nil {
		return nil, err
	}

	return &Session{
		Id:   sid,
		Key:  c.Value,
		User: u,
	}, nil
}
예제 #24
0
func (h *Handler) handleUser(w http.ResponseWriter, r *http.Request) {
	segments := strings.Split(strings.Trim(r.URL.Path, "/"), "/")
	username := segments[2]

	s, err := session.Parse(r)
	if err != nil {
		logger.Error(w, err)
	} else {
		err = s.Save(w, true)
		if err != nil {
			logger.Error(w, err)
		}
	}

	var owner bool
	var u *user.User
	if s != nil && s.User.Username == username {
		owner = true
		u = s.User
	} else {
		owner = false
		u, err = user.LoadByUsername(username)
		if err != nil {
			logger.Error(w, err)
			h.serveNotFound(w, r)
			return
		}
	}

	msg, _ := flashdata.Get(w, r)

	m := map[string]interface{}{
		"baseurl": config.Get("baseurl"),
		"session": s,
		"message": msg,
		"user":    u,
		"owner":   owner,
	}

	h.Templates.ExecuteTemplate(w, "user.html", m)
}
예제 #25
0
func main() {
	switch len(os.Args) {
	case 1:
		break
	case 2:
		err := os.Chdir(os.Args[1])
		if err != nil {
			panic(err)
		}
		break
	default:
		return
	}

	err := config.Load("./data/data.db")
	if err != nil {
		panic(err)
	}

	config.Dump(os.Stdout)

	h, err := handler.New()
	if err != nil {
		panic(err)
	}

	err = ioutil.WriteFile("./pid", []byte(strconv.Itoa(os.Getpid())), 0644)
	if err != nil {
		panic(err)
	}

	http.Handle("/", h)
	err = http.ListenAndServe(config.Get("bind"), nil)
	if err != nil {
		panic(err)
	}
}
예제 #26
0
func SendVerify(uid int64, email string, activate bool) error {
	// Add verify
	vkey, err := uuid4.New()
	if err != nil {
		return err
	}

	q := `
        INSERT INTO user_verify
        VALUES(
            NULL
            , ?
            , ?
            , ?
            , ?
            , ?
        );
    `

	params := []interface{}{
		vkey,
		uid,
		time.Now().Unix() + VERIFY_OFFSET,
		time.Now().Unix(),
		time.Now().Unix(),
	}

	_, err = dao.Exec(q, params)
	if err != nil {
		return err
	}

	// Send verify email
	url := fmt.Sprintf("%s/verify/%s", config.Get("baseurl"), vkey)

	loadTemplates()

	tpl := "reset"
	subject := "Timesheet - Password reset"
	if activate {
		tpl = "activate"
		subject = "Timesheet - Please active your account"
	}

	html := new(bytes.Buffer)
	Templates.ExecuteTemplate(html, fmt.Sprintf("%s.html", tpl), url)

	text := new(bytes.Buffer)
	Templates.ExecuteTemplate(text, fmt.Sprintf("%s.txt", tpl), url)

	m := awsses.New(
		config.Get("awsses_sender"),
		email,
		subject,
		html.String(),
		text.String())

	return m.Send(
		config.Get("awsses_baseurl"),
		config.Get("awsses_accesskey"),
		config.Get("awsses_secretkey"))
}