Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
nexpie-grafana-theme
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kornkitt Poolsup
nexpie-grafana-theme
Commits
c8bc0b3b
Commit
c8bc0b3b
authored
Jun 08, 2015
by
Torkel Ödegaard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Lots of work on user password reset, #1456
parent
aa4d60c2
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
129 additions
and
50 deletions
+129
-50
pkg/api/api.go
+1
-1
pkg/api/dtos/user.go
+6
-0
pkg/api/password.go
+24
-2
pkg/models/emails.go
+9
-0
pkg/services/notifications/codes.go
+32
-3
pkg/services/notifications/codes_test.go
+35
-0
pkg/services/notifications/notifications.go
+18
-42
public/app/controllers/resetPasswordCtrl.js
+4
-2
No files found.
pkg/api/api.go
View file @
c8bc0b3b
...
...
@@ -46,7 +46,7 @@ func Register(r *macaron.Macaron) {
r
.
Get
(
"/user/password/reset"
,
Index
)
r
.
Post
(
"/api/user/password/send-reset-email"
,
bind
(
dtos
.
SendResetPasswordEmailForm
{}),
wrap
(
SendResetPasswordEmail
))
r
.
Post
(
"/api/user/password/reset"
,
wrap
(
ViewResetPasswordForm
))
r
.
Post
(
"/api/user/password/reset"
,
bind
(
dtos
.
ResetUserPasswordForm
{}),
wrap
(
ResetPassword
))
// dashboard snapshots
r
.
Post
(
"/api/snapshots/"
,
bind
(
m
.
CreateDashboardSnapshotCommand
{}),
CreateDashboardSnapshot
)
...
...
pkg/api/dtos/user.go
View file @
c8bc0b3b
...
...
@@ -31,3 +31,9 @@ type AdminUserListItem struct {
type
SendResetPasswordEmailForm
struct
{
UserOrEmail
string
`json:"userOrEmail" binding:"Required"`
}
type
ResetUserPasswordForm
struct
{
Code
string
`json:"code"`
NewPassword
string
`json:"newPassword"`
ConfirmPassword
string
`json:"confirmPassword"`
}
pkg/api/password.go
View file @
c8bc0b3b
...
...
@@ -5,6 +5,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/middleware"
m
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/util"
)
func
SendResetPasswordEmail
(
c
*
middleware
.
Context
,
form
dtos
.
SendResetPasswordEmailForm
)
Response
{
...
...
@@ -22,6 +23,27 @@ func SendResetPasswordEmail(c *middleware.Context, form dtos.SendResetPasswordEm
return
ApiSuccess
(
"Email sent"
)
}
func
ViewResetPasswordForm
(
c
*
middleware
.
Context
)
Response
{
return
ApiSuccess
(
"Email sent"
)
func
ResetPassword
(
c
*
middleware
.
Context
,
form
dtos
.
ResetUserPasswordForm
)
Response
{
query
:=
m
.
ValidateResetPasswordCodeQuery
{
Code
:
form
.
Code
}
if
err
:=
bus
.
Dispatch
(
&
query
);
err
!=
nil
{
if
err
==
m
.
ErrInvalidEmailCode
{
return
ApiError
(
400
,
"Invalid or expired reset password code"
,
nil
)
}
return
ApiError
(
500
,
"Unknown error validating email code"
,
err
)
}
if
form
.
NewPassword
!=
form
.
ConfirmPassword
{
return
ApiError
(
400
,
"Passwords do not match"
,
nil
)
}
cmd
:=
m
.
ChangeUserPasswordCommand
{}
cmd
.
UserId
=
query
.
Result
.
Id
cmd
.
NewPassword
=
util
.
EncodePassword
(
form
.
NewPassword
,
query
.
Result
.
Salt
)
if
err
:=
bus
.
Dispatch
(
&
cmd
);
err
!=
nil
{
return
ApiError
(
500
,
"Failed to change user password"
,
err
)
}
return
ApiSuccess
(
"User password changed"
)
}
pkg/models/emails.go
View file @
c8bc0b3b
package
models
import
"errors"
var
ErrInvalidEmailCode
=
errors
.
New
(
"Invalid or expired email code"
)
type
SendEmailCommand
struct
{
To
[]
string
From
string
...
...
@@ -13,6 +17,11 @@ type SendResetPasswordEmailCommand struct {
User
*
User
}
type
ValidateResetPasswordCodeQuery
struct
{
Code
string
Result
*
User
}
// create mail content
func
(
m
*
SendEmailCommand
)
Content
()
string
{
contentType
:=
"text/html; charset=UTF-8"
...
...
pkg/services/notifications/codes.go
View file @
c8bc0b3b
...
...
@@ -7,12 +7,15 @@ import (
"time"
"github.com/Unknwon/com"
m
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
)
const
timeLimitCodeLength
=
12
+
6
+
40
// create a time limit code
// code format: 12 length date time string + 6 minutes string + 40 sha1 encoded string
func
C
reateTimeLimitCode
(
data
string
,
minutes
int
,
startInf
interface
{})
string
{
func
c
reateTimeLimitCode
(
data
string
,
minutes
int
,
startInf
interface
{})
string
{
format
:=
"200601021504"
var
start
,
end
time
.
Time
...
...
@@ -42,11 +45,14 @@ func CreateTimeLimitCode(data string, minutes int, startInf interface{}) string
}
// verify time limit code
func
VerifyTimeLimitCode
(
data
string
,
minutes
int
,
code
string
)
bool
{
func
validateUserEmailCode
(
user
*
m
.
User
,
code
string
)
bool
{
if
len
(
code
)
<=
18
{
return
false
}
minutes
:=
setting
.
EmailCodeValidMinutes
code
=
code
[
:
timeLimitCodeLength
]
// split code
start
:=
code
[
:
12
]
lives
:=
code
[
12
:
18
]
...
...
@@ -55,7 +61,9 @@ func VerifyTimeLimitCode(data string, minutes int, code string) bool {
}
// right active code
retCode
:=
CreateTimeLimitCode
(
data
,
minutes
,
start
)
data
:=
com
.
ToStr
(
user
.
Id
)
+
user
.
Email
+
user
.
Login
+
user
.
Password
+
user
.
Rands
retCode
:=
createTimeLimitCode
(
data
,
minutes
,
start
)
fmt
.
Printf
(
"code : %s
\n
code2: %s"
,
retCode
,
code
)
if
retCode
==
code
&&
minutes
>
0
{
// check time is expired or not
before
,
_
:=
time
.
ParseInLocation
(
"200601021504"
,
start
,
time
.
Local
)
...
...
@@ -67,3 +75,24 @@ func VerifyTimeLimitCode(data string, minutes int, code string) bool {
return
false
}
func
getLoginForEmailCode
(
code
string
)
string
{
if
len
(
code
)
<=
timeLimitCodeLength
{
return
""
}
// use tail hex username query user
hexStr
:=
code
[
timeLimitCodeLength
:
]
b
,
_
:=
hex
.
DecodeString
(
hexStr
)
return
string
(
b
)
}
func
createUserEmailCode
(
u
*
m
.
User
,
startInf
interface
{})
string
{
minutes
:=
setting
.
EmailCodeValidMinutes
data
:=
com
.
ToStr
(
u
.
Id
)
+
u
.
Email
+
u
.
Login
+
u
.
Password
+
u
.
Rands
code
:=
createTimeLimitCode
(
data
,
minutes
,
startInf
)
// add tail hex username
code
+=
hex
.
EncodeToString
([]
byte
(
u
.
Login
))
return
code
}
pkg/services/notifications/codes_test.go
0 → 100644
View file @
c8bc0b3b
package
notifications
import
(
"testing"
m
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
.
"github.com/smartystreets/goconvey/convey"
)
func
TestEmailCodes
(
t
*
testing
.
T
)
{
Convey
(
"When generating code"
,
t
,
func
()
{
setting
.
EmailCodeValidMinutes
=
120
user
:=
&
m
.
User
{
Id
:
10
,
Email
:
"t@a.com"
,
Login
:
"asd"
,
Password
:
"1"
,
Rands
:
"2"
}
code
:=
createUserEmailCode
(
user
,
nil
)
Convey
(
"getLoginForCode should return login"
,
func
()
{
login
:=
getLoginForEmailCode
(
code
)
So
(
login
,
ShouldEqual
,
"asd"
)
})
Convey
(
"Can verify valid code"
,
func
()
{
So
(
validateUserEmailCode
(
user
,
code
),
ShouldBeTrue
)
})
Convey
(
"Cannot verify in-valid code"
,
func
()
{
code
=
"ASD"
So
(
validateUserEmailCode
(
user
,
code
),
ShouldBeFalse
)
})
})
}
pkg/services/notifications/notifications.go
View file @
c8bc0b3b
...
...
@@ -2,12 +2,10 @@ package notifications
import
(
"bytes"
"encoding/hex"
"errors"
"html/template"
"path/filepath"
"github.com/Unknwon/com"
"github.com/grafana/grafana/pkg/bus"
m
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
...
...
@@ -19,6 +17,7 @@ var tmplResetPassword = "reset_password.html"
func
Init
()
error
{
bus
.
AddHandler
(
"email"
,
sendResetPasswordEmail
)
bus
.
AddHandler
(
"email"
,
validateResetPasswordCode
)
mailTemplates
=
template
.
New
(
"name"
)
mailTemplates
.
Funcs
(
template
.
FuncMap
{
...
...
@@ -55,7 +54,7 @@ func sendResetPasswordEmail(cmd *m.SendResetPasswordEmailCommand) error {
var
buffer
bytes
.
Buffer
var
data
=
getMailTmplData
(
cmd
.
User
)
code
:=
CreateUserActive
Code
(
cmd
.
User
,
nil
)
code
:=
createUserEmail
Code
(
cmd
.
User
,
nil
)
data
[
"Code"
]
=
code
mailTemplates
.
ExecuteTemplate
(
&
buffer
,
tmplResetPassword
,
data
)
...
...
@@ -70,44 +69,21 @@ func sendResetPasswordEmail(cmd *m.SendResetPasswordEmailCommand) error {
return
nil
}
func
CreateUserActiveCode
(
u
*
m
.
User
,
startInf
interface
{})
string
{
minutes
:=
setting
.
EmailCodeValidMinutes
data
:=
com
.
ToStr
(
u
.
Id
)
+
u
.
Email
+
u
.
Login
+
u
.
Password
+
u
.
Rands
code
:=
CreateTimeLimitCode
(
data
,
minutes
,
startInf
)
func
validateResetPasswordCode
(
query
*
m
.
ValidateResetPasswordCodeQuery
)
error
{
login
:=
getLoginForEmailCode
(
query
.
Code
)
if
login
==
""
{
return
m
.
ErrInvalidEmailCode
}
// add tail hex username
code
+=
hex
.
EncodeToString
([]
byte
(
u
.
Login
))
return
code
}
userQuery
:=
m
.
GetUserByLoginQuery
{
LoginOrEmail
:
login
}
if
err
:=
bus
.
Dispatch
(
&
userQuery
);
err
!=
nil
{
return
err
}
// // verify active code when active account
// func VerifyUserActiveCode(code string) (user *User) {
// minutes := setting.Service.ActiveCodeLives
//
// if user = getVerifyUser(code); user != nil {
// // time limit code
// prefix := code[:base.TimeLimitCodeLength]
// data := com.ToStr(user.Id) + user.Email + user.LowerName + user.Passwd + user.Rands
//
// if base.VerifyTimeLimitCode(data, minutes, prefix) {
// return user
// }
// }
// return nil
// }
//
// // verify active code when active account
// func VerifyUserActiveCode(code string) (user *User) {
// minutes := setting.Service.ActiveCodeLives
//
// if user = getVerifyUser(code); user != nil {
// // time limit code
// prefix := code[:base.TimeLimitCodeLength]
// data := com.ToStr(user.Id) + user.Email + user.LowerName + user.Passwd + user.Rands
//
// if base.VerifyTimeLimitCode(data, minutes, prefix) {
// return user
// }
// }
// return nil
// }
if
!
validateUserEmailCode
(
userQuery
.
Result
,
query
.
Code
)
{
return
m
.
ErrInvalidEmailCode
}
query
.
Result
=
userQuery
.
Result
return
nil
}
public/app/controllers/resetPasswordCtrl.js
View file @
c8bc0b3b
...
...
@@ -12,8 +12,10 @@ function (angular) {
$scope
.
formModel
=
{};
$scope
.
mode
=
'send'
;
if
(
$location
.
search
().
code
)
{
var
params
=
$location
.
search
();
if
(
params
.
code
)
{
$scope
.
mode
=
'reset'
;
$scope
.
formModel
.
code
=
params
.
code
;
}
$scope
.
sendResetEmail
=
function
()
{
...
...
@@ -33,7 +35,7 @@ function (angular) {
return
;
}
backendSrv
.
post
(
'/api/user/password/
send-reset-email
'
,
$scope
.
formModel
).
then
(
function
()
{
backendSrv
.
post
(
'/api/user/password/
reset
'
,
$scope
.
formModel
).
then
(
function
()
{
$location
.
path
(
'login'
);
});
};
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment