2021-05-12 22:09:41 +08:00
|
|
|
// Copyright 2021 The casbin Authors. All Rights Reserved.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2021-05-12 21:38:31 +08:00
|
|
|
package object
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"math/rand"
|
|
|
|
"time"
|
2021-05-18 19:42:03 +08:00
|
|
|
|
2021-05-18 20:11:03 +08:00
|
|
|
"github.com/astaxie/beego"
|
2021-05-24 01:27:03 +08:00
|
|
|
"github.com/casdoor/casdoor/util"
|
2021-05-18 19:42:03 +08:00
|
|
|
"xorm.io/core"
|
2021-05-12 21:38:31 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
type VerificationRecord struct {
|
2021-05-24 01:27:03 +08:00
|
|
|
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
|
|
|
|
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
|
|
|
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
|
|
|
|
|
|
|
RemoteAddr string `xorm:"varchar(100)"`
|
|
|
|
Type string `xorm:"varchar(10)"`
|
2021-05-24 01:18:21 +08:00
|
|
|
User string `xorm:"varchar(100) notnull"`
|
2021-05-24 01:02:38 +08:00
|
|
|
Provider string `xorm:"varchar(100) notnull"`
|
2021-05-12 21:38:31 +08:00
|
|
|
Receiver string `xorm:"varchar(100) notnull"`
|
|
|
|
Code string `xorm:"varchar(10) notnull"`
|
|
|
|
Time int64 `xorm:"notnull"`
|
|
|
|
IsUsed bool
|
|
|
|
}
|
|
|
|
|
2021-05-24 01:18:21 +08:00
|
|
|
func SendVerificationCodeToEmail(user *User, provider *Provider, remoteAddr string, dest string) string {
|
2021-05-24 01:02:38 +08:00
|
|
|
if provider == nil {
|
|
|
|
return "Please set an Email provider first"
|
|
|
|
}
|
|
|
|
|
2021-05-15 10:13:12 +08:00
|
|
|
title := "Casdoor Verification Code"
|
|
|
|
sender := "Casdoor"
|
2021-05-12 21:38:31 +08:00
|
|
|
code := getRandomCode(5)
|
|
|
|
content := fmt.Sprintf("You have requested a verification code at Casdoor. Here is your code: %s, please enter in 5 minutes.", code)
|
|
|
|
|
2021-05-24 01:18:21 +08:00
|
|
|
if result := AddToVerificationRecord(user, provider, remoteAddr, "Email", dest, code); len(result) != 0 {
|
2021-05-12 21:38:31 +08:00
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2021-05-24 01:02:38 +08:00
|
|
|
msg, err := SendEmail(provider, title, content, dest, sender)
|
2021-05-15 10:13:12 +08:00
|
|
|
if msg != "" {
|
|
|
|
return msg
|
|
|
|
}
|
|
|
|
if err != nil {
|
2021-05-12 21:38:31 +08:00
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2021-05-24 01:18:21 +08:00
|
|
|
func SendVerificationCodeToPhone(user *User, provider *Provider, remoteAddr string, dest string) string {
|
2021-05-24 01:02:38 +08:00
|
|
|
if provider == nil {
|
|
|
|
return "Please set a SMS provider first"
|
|
|
|
}
|
|
|
|
|
2021-05-12 22:09:41 +08:00
|
|
|
code := getRandomCode(5)
|
2021-05-24 01:18:21 +08:00
|
|
|
if result := AddToVerificationRecord(user, provider, remoteAddr, "SMS", dest, code); len(result) != 0 {
|
2021-05-12 22:09:41 +08:00
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2021-05-24 01:02:38 +08:00
|
|
|
return SendCodeToPhone(provider, dest, code)
|
2021-05-12 22:09:41 +08:00
|
|
|
}
|
|
|
|
|
2021-05-24 01:18:21 +08:00
|
|
|
func AddToVerificationRecord(user *User, provider *Provider, remoteAddr, recordType, dest, code string) string {
|
2021-05-12 21:38:31 +08:00
|
|
|
var record VerificationRecord
|
|
|
|
record.RemoteAddr = remoteAddr
|
2021-05-18 19:42:03 +08:00
|
|
|
record.Type = recordType
|
2021-05-24 01:18:21 +08:00
|
|
|
if user != nil {
|
|
|
|
record.User = user.GetId()
|
|
|
|
}
|
2021-05-12 21:38:31 +08:00
|
|
|
has, err := adapter.Engine.Get(&record)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
now := time.Now().Unix()
|
|
|
|
|
2021-05-24 01:02:38 +08:00
|
|
|
if has && now-record.Time < 60 {
|
2021-05-12 21:38:31 +08:00
|
|
|
return "You can only send one code in 60s."
|
|
|
|
}
|
|
|
|
|
2021-05-24 01:27:03 +08:00
|
|
|
record.Owner = provider.Owner
|
|
|
|
record.Name = util.GenerateId()
|
|
|
|
record.CreatedTime = util.GetCurrentTime()
|
|
|
|
if user != nil {
|
|
|
|
record.User = user.GetId()
|
|
|
|
}
|
|
|
|
record.Provider = provider.Name
|
|
|
|
|
2021-05-12 21:38:31 +08:00
|
|
|
record.Receiver = dest
|
|
|
|
record.Code = code
|
|
|
|
record.Time = now
|
|
|
|
record.IsUsed = false
|
|
|
|
|
|
|
|
if has {
|
2021-05-18 19:42:03 +08:00
|
|
|
_, err = adapter.Engine.ID(core.PK{remoteAddr, recordType}).AllCols().Update(record)
|
2021-05-12 21:38:31 +08:00
|
|
|
} else {
|
|
|
|
_, err = adapter.Engine.Insert(record)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2021-05-18 20:11:03 +08:00
|
|
|
func getVerificationRecord(dest string) *VerificationRecord {
|
2021-05-12 21:38:31 +08:00
|
|
|
var record VerificationRecord
|
|
|
|
record.Receiver = dest
|
|
|
|
has, err := adapter.Engine.Desc("time").Where("is_used = 0").Get(&record)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
if !has {
|
2021-05-18 20:11:03 +08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return &record
|
|
|
|
}
|
|
|
|
|
|
|
|
func CheckVerificationCode(dest, code string) string {
|
|
|
|
record := getVerificationRecord(dest)
|
|
|
|
|
|
|
|
if record == nil {
|
2021-05-12 21:38:31 +08:00
|
|
|
return "Code has not been sent yet!"
|
|
|
|
}
|
|
|
|
|
2021-05-18 20:11:03 +08:00
|
|
|
timeout, err := beego.AppConfig.Int64("verificationCodeTimeout")
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
2021-05-12 21:38:31 +08:00
|
|
|
now := time.Now().Unix()
|
2021-05-18 20:11:03 +08:00
|
|
|
if now-record.Time > timeout*60 {
|
|
|
|
return fmt.Sprintf("You should verify your code in %d min!", timeout)
|
2021-05-12 21:38:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if record.Code != code {
|
|
|
|
return "Wrong code!"
|
|
|
|
}
|
|
|
|
|
2021-05-18 20:11:03 +08:00
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
func DisableVerificationCode(dest string) {
|
|
|
|
record := getVerificationRecord(dest)
|
|
|
|
if record == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-05-12 21:38:31 +08:00
|
|
|
record.IsUsed = true
|
2021-05-24 01:27:03 +08:00
|
|
|
_, err := adapter.Engine.ID(core.PK{record.Owner, record.Name}).AllCols().Update(record)
|
2021-05-12 21:38:31 +08:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// from Casnode/object/validateCode.go line 116
|
|
|
|
var stdNums = []byte("0123456789")
|
|
|
|
|
|
|
|
func getRandomCode(length int) string {
|
|
|
|
var result []byte
|
|
|
|
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
|
|
|
for i := 0; i < length; i++ {
|
|
|
|
result = append(result, stdNums[r.Intn(len(stdNums))])
|
|
|
|
}
|
|
|
|
return string(result)
|
|
|
|
}
|