Create & Init Project...

This commit is contained in:
2019-04-22 18:49:16 +08:00
commit fc4fa37393
25440 changed files with 4054998 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
package(default_visibility = ["//visibility:public"])
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/service/main/secure/cmd:all-srcs",
"//app/service/main/secure/conf:all-srcs",
"//app/service/main/secure/dao:all-srcs",
"//app/service/main/secure/http:all-srcs",
"//app/service/main/secure/model:all-srcs",
"//app/service/main/secure/rpc/client:all-srcs",
"//app/service/main/secure/rpc/server:all-srcs",
"//app/service/main/secure/service:all-srcs",
],
tags = ["automanaged"],
)

View File

@@ -0,0 +1,78 @@
### v1.13.1
> 1.去除 ip 包使用
### v1.13.0
> 1.location接口Info2改为InfoComplete
### V1.11.0
> 1.add server out ip
### V1.10.0
> 1.update ut
### V1.9.1
> 1.update habase client
### V1.9.0
> 1.new server && new verify or auth
### V1.8.0
> 1.bm
### V1.7.0
> 1.move path
> 2.update build
### V1.6.1
> 1.update CONTRIBUTORS.md and add check log
### V1.6.0
> 1.添加查询ip是否归属用户常用登录地接口
### V1.5.0
> 1.迁移异常日志到hbase
### V1.4.1
> 1.使用hash rowkey
### V1.4.0
> 1. 迁移hbase
### V1.3.1
> 1.修复异地登陆判断
### V1.3.0
> 1.二次登陆验证
### V1.2.0
> 1.合并进入大仓库
### V1.1.7
> 1.添加服务器出口ip过滤
### V1.1.6
> 1.修复redis 错误
### V1.1.5
> 1.修复redis过期时间
### V1.1.4
> 1.修复redis 空值错误
### V1.1.3
> 1.添加随机比率
### V1.1.1
> 1.调整异地规则
### V1.1.0
> 1.升级到go-comon7
### v1.0.0
> 1.异地登陆提醒
### V1.0.1
> 1.msg commit
### V1.0.2
> 1.修复sql

View File

@@ -0,0 +1,14 @@
# Owner
zhaogangtao
wanghuan01
zhoujiahui
# Author
zhaogangtao
wanghuan01
zhoujiahui
# Reviewer
zhaogangtao
wanghuan01
zhoujiahui

View File

@@ -0,0 +1,16 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- wanghuan01
- zhaogangtao
- zhoujiahui
labels:
- main
- service
- service/main/secure
options:
no_parent_owners: true
reviewers:
- wanghuan01
- zhaogangtao
- zhoujiahui

View File

@@ -0,0 +1,8 @@
#### secure-service
### 项目简介
> 账号异地登陆提醒
##### 依赖包
> 1.公共包go-common

View File

@@ -0,0 +1,43 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_binary",
)
go_library(
name = "go_default_library",
srcs = ["main.go"],
data = ["secure-service-test.toml"],
importpath = "go-common/app/service/main/secure/cmd",
tags = ["automanaged"],
visibility = ["//visibility:private"],
deps = [
"//app/service/main/secure/conf:go_default_library",
"//app/service/main/secure/http:go_default_library",
"//app/service/main/secure/rpc/server:go_default_library",
"//app/service/main/secure/service:go_default_library",
"//library/log:go_default_library",
"//library/net/rpc:go_default_library",
"//library/net/trace:go_default_library",
],
)
go_binary(
name = "cmd",
embed = [":go_default_library"],
visibility = ["//visibility:public"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,63 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"time"
"go-common/app/service/main/secure/conf"
"go-common/app/service/main/secure/http"
rpc "go-common/app/service/main/secure/rpc/server"
"go-common/app/service/main/secure/service"
"go-common/library/log"
xrpc "go-common/library/net/rpc"
"go-common/library/net/trace"
)
var (
srv *service.Service
rpcSvr *xrpc.Server
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
log.Error("conf.Init() error(%v)", err)
panic(err)
}
log.Init(conf.Conf.Log)
defer log.Close()
trace.Init(conf.Conf.Tracer)
defer trace.Close()
log.Info("credit-timer start")
srv = service.New(conf.Conf)
rpcSvr = rpc.New(conf.Conf, srv)
http.Init(srv)
signalHandler()
}
func signalHandler() {
var (
err error
ch = make(chan os.Signal, 1)
)
signal.Notify(ch, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
si := <-ch
switch si {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
rpcSvr.Close()
time.Sleep(time.Second)
log.Info("get a signal %s, stop the consume process", si.String())
if err = srv.Close(); err != nil {
log.Error("srv close consumer error(%v)", err)
}
return
case syscall.SIGHUP:
default:
return
}
}
}

View File

@@ -0,0 +1,120 @@
[bm]
addr = "0.0.0.0:6812"
maxListen = 1000
timeout = "1s"
[httpClient]
key = "3c4e41f926e51656"
secret ="26a2095b60c24154521d24ae62b885bb"
dial = "500ms"
timeout = "2s"
keepAlive = "60s"
timer = 10
[httpClient.breaker]
window ="10s"
sleep ="10ms"
bucket = 10
ratio = 0.5
request = 100
[databus]
key = "0QNB0ZgFozbKUCQhbTq8"
secret = "0QNB0ZgFozbKUCQhbTq9"
group = "PassportBinlog-Login-S"
topic = "Passport-T"
action = "sub"
offset = "new"
buffer = 2048
name = "secure-service/databus"
proto = "tcp"
addr = "172.18.33.50:6205"
idle = 1
active = 1
dialTimeout = "1s"
readTimeout = "60s"
writeTimeout = "1s"
idleTimeout = "10s"
[mysql]
[mysql.secure]
addr = "172.22.34.101:3309"
dsn = "secure:cvETlGWr360LVzQPeJwydStxmA78Z4hX@tcp(172.22.34.101:3309)/bilibili_secure?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 3
idle = 1
idleTimeout ="4h"
queryTimeout = "100ms"
execTimeout = "100ms"
tranTimeout = "200ms"
[mysql.secure.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[mysql.ddl]
addr = "172.22.34.101:3309"
dsn = "secure_ddl:c1GoSPd8O2KgBvkeRTbWMufNyzHiw6aV@tcp(172.22.34.101:3309)/bilibili_secure?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 3
idle = 1
idleTimeout ="4h"
queryTimeout = "100ms"
execTimeout = "100ms"
tranTimeout = "200ms"
[mysql.ddl.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[rpcServer]
proto = "tcp"
addr = "0.0.0.0:6819"
weight = 10
[locationrpc]
timeout = "30s"
[redis]
name = "secure-service/secure"
proto = "tcp"
addr = "172.18.33.61:6839"
idle = 2
active = 20
dialTimeout = "100ms"
readTimeout = "350ms"
writeTimeout = "350ms"
idleTimeout = "80s"
expire = "1h"
doubleCheck="720h"
[memcache]
name = "secure-service"
proto = "tcp"
addr = "172.18.33.61:11212"
idle = 1
active = 10
dialTimeout = "100ms"
readTimeout = "200ms"
writeTimeout = "200ms"
idleTimeout = "80s"
expire = "9h"
[hbase]
master = ""
meta = ""
dialTimeout = "1s"
readTimeout = "10s"
readsTimeout = "10s"
writeTimeout = "10s"
writesTimeout = "10s"
[hbase.zookeeper]
root = ""
addrs = ["172.18.33.75:2181" ]
timeout = "30s"
[Expect]
Top = 3
Count =2
closeCount = 1000
Rand = 1

View File

@@ -0,0 +1,43 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["conf.go"],
importpath = "go-common/app/service/main/secure/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/cache/memcache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/conf:go_default_library",
"//library/database/hbase.v2:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/verify:go_default_library",
"//library/net/rpc:go_default_library",
"//library/net/trace:go_default_library",
"//library/queue/databus:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/BurntSushi/toml:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,145 @@
package conf
import (
"errors"
"flag"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
"go-common/library/conf"
"go-common/library/database/sql"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
"go-common/library/net/rpc"
"go-common/library/net/trace"
"go-common/library/queue/databus"
"go-common/library/time"
"go-common/library/database/hbase.v2"
"github.com/BurntSushi/toml"
)
// Conf global variable.
var (
Conf = &Config{}
client *conf.Client
confPath string
)
// Config struct of conf.
type Config struct {
// app
App *bm.App
// tracer
Tracer *trace.Config
// goroutine sleep
Tick time.Duration
// http server
BM *bm.ServerConfig
// log
Log *log.Config
// verify
Verify *verify.Config
LocationRPC *rpc.ClientConfig
DataBus *databus.Config
Mysql *Mysql
Expect *Expect
// redis
Redis *Redis
// httpClient
HTTPClient *bm.ClientConfig
// rpc
RPCServer *rpc.ServerConfig
// HBase
HBase *HBaseConfig
// mc
Memcache *Memcache
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// HBaseConfig extra hbase config for compatible
type HBaseConfig struct {
*hbase.Config
WriteTimeout time.Duration
ReadTimeout time.Duration
}
// Memcache mc config.
type Memcache struct {
*memcache.Config
Expire time.Duration
}
// Mysql conf.
type Mysql struct {
Secure *sql.Config
DDL *sql.Config
}
// Redis redis conf.
type Redis struct {
*redis.Config
Expire time.Duration
DoubleCheck time.Duration
}
// Expect Login expection config.
type Expect struct {
Top int64 // login loc count.
Count int64 // login time count.
CloseCount int64 // user close count.
Rand int64 // rand ratio
DoubleCheck int64 // double login check location count.
}
// Init create config instance.
func Init() (err error) {
if confPath != "" {
return local()
}
return remote()
}
func local() (err error) {
_, err = toml.DecodeFile(confPath, &Conf)
return
}
func remote() (err error) {
if client, err = conf.New(); err != nil {
return
}
if err = load(); err != nil {
return
}
go func() {
for range client.Event() {
log.Info("config reload")
if load() != nil {
log.Error("config reload error (%v)", err)
}
}
}()
return
}
func load() (err error) {
var (
s string
ok bool
tmpConf *Config
)
if s, ok = client.Toml2(); !ok {
return errors.New("load config center error")
}
if _, err = toml.Decode(s, &tmpConf); err != nil {
return errors.New("could not decode config")
}
*Conf = *tmpConf
return
}

View File

@@ -0,0 +1,67 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"hbase.go",
"http.go",
"memcache.go",
"redis.go",
],
importpath = "go-common/app/service/main/secure/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/secure/conf:go_default_library",
"//app/service/main/secure/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/hbase.v2:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/tsuna/gohbase/hrpc:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"hbase_test.go",
"http_test.go",
"memcache_test.go",
"redis_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/secure/conf:go_default_library",
"//app/service/main/secure/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/bouk/monkey:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,52 @@
package dao
import (
"time"
"go-common/app/service/main/secure/conf"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
"go-common/library/database/sql"
bm "go-common/library/net/http/blademaster"
"go-common/library/database/hbase.v2"
)
// Dao struct info of Dao.
type Dao struct {
db *sql.DB
ddldb *sql.DB
c *conf.Config
redis *redis.Pool
hbase *hbase.Client
locsExpire int32
expire int64
doubleCheckExpire int64
mc *memcache.Pool
// http
httpClient *bm.Client
}
// New new a Dao and return.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
redis: redis.NewPool(c.Redis.Config),
expire: int64(time.Duration(c.Redis.Expire) / time.Second),
doubleCheckExpire: int64(time.Duration(c.Redis.DoubleCheck) / time.Second),
db: sql.NewMySQL(c.Mysql.Secure),
ddldb: sql.NewMySQL(c.Mysql.DDL),
hbase: hbase.NewClient(c.HBase.Config),
mc: memcache.NewPool(c.Memcache.Config),
locsExpire: int32(time.Duration(c.Memcache.Expire) / time.Second),
httpClient: bm.NewClient(c.HTTPClient),
}
return
}
// Close close connections of mc, redis, db.
func (d *Dao) Close() {
if d.db != nil {
d.db.Close()
}
}

View File

@@ -0,0 +1,37 @@
package dao
import (
"flag"
"os"
"testing"
"go-common/app/service/main/secure/conf"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.account.secure-service")
flag.Set("conf_appid", "main.account.secure-service")
flag.Set("conf_token", "02bebea2b9e0b8d5b0433b2a59b8bc68")
flag.Set("tree_id", "2864")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_env", "10")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../cmd/secure-service-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
os.Exit(m.Run())
}

View File

@@ -0,0 +1,172 @@
package dao
import (
"bytes"
"context"
"crypto/md5"
"encoding/binary"
"fmt"
"io"
"strconv"
"time"
"go-common/app/service/main/secure/model"
"go-common/library/log"
xtime "go-common/library/time"
"github.com/tsuna/gohbase/hrpc"
)
var (
tableLog = "ugc:login_log"
familyTS = "ts"
familyTSB = []byte(familyTS)
tableSecure = "ugc:secure"
familyEcpt = "ecpt"
familyEcptB = []byte(familyEcpt)
columnid = "id"
columnloc = "loc"
columntp = "tp"
columnip = "ip"
columnts = "ts"
// familyFB = "feedback"
// familyFBB = []byte(familyFB)
)
// rowKey return key string.
func rowKey(mid int64) string {
sum := md5.Sum([]byte(strconv.FormatInt(mid, 10)))
return fmt.Sprintf("%x", sum)
}
func exKey(mid, ts int64, ip uint32) string {
return fmt.Sprintf("%d%d_%d_%d", mid%10, mid, ts, ip)
}
func exStartkey(mid int64) string {
return fmt.Sprintf("%d%d", mid%10, mid)
}
func exStopKey(mid int64) string {
return fmt.Sprintf("%d%d", mid%10, mid+1)
}
// AddLocs add login log.
func (d *Dao) AddLocs(c context.Context, mid, locid, ts int64) (err error) {
var (
locB = make([]byte, 8)
key = rowKey(mid)
column = strconv.FormatInt(ts, 10)
ctx, cancel = context.WithTimeout(c, time.Duration(d.c.HBase.WriteTimeout))
)
defer cancel()
binary.BigEndian.PutUint64(locB, uint64(locid))
values := map[string]map[string][]byte{familyTS: {column: locB}}
if _, err = d.hbase.PutStr(ctx, tableLog, key, values); err != nil {
log.Error("hbase.Put error(%v)", err)
}
return
}
// Locs get all login location.
func (d *Dao) Locs(c context.Context, mid int64) (locs map[int64]int64, err error) {
var (
result *hrpc.Result
key = rowKey(mid)
ctx, cancel = context.WithTimeout(c, time.Duration(d.c.HBase.ReadTimeout))
)
defer cancel()
if result, err = d.hbase.GetStr(ctx, tableLog, key); err != nil {
log.Error("d.hbase.Get error(%v)", err)
return
}
if result == nil {
return
}
locs = make(map[int64]int64)
for _, c := range result.Cells {
if c != nil && len(c.Value) == 8 && bytes.Equal(c.Family, familyTSB) {
locid := int64(binary.BigEndian.Uint64(c.Value))
locs[locid]++
}
}
return
}
// AddException add feedback.
func (d *Dao) AddException(c context.Context, l *model.Log) (err error) {
var (
idB = make([]byte, 8)
ipB = make([]byte, 8)
tsB = make([]byte, 8)
key = exKey(l.Mid, int64(l.Time), l.IP)
ctx, cancel = context.WithTimeout(c, time.Duration(d.c.HBase.WriteTimeout))
)
defer cancel()
binary.BigEndian.PutUint64(idB, uint64(l.LocationID))
binary.BigEndian.PutUint64(ipB, uint64(l.IP))
binary.BigEndian.PutUint64(tsB, uint64(l.Time))
values := map[string]map[string][]byte{familyEcpt: {
columnid: idB,
columnloc: []byte(l.Location),
columnts: tsB,
columnip: ipB,
}}
if _, err = d.hbase.PutStr(ctx, tableSecure, key, values); err != nil {
log.Error("hbase.Put error(%v)", err)
}
return
}
// AddFeedBack add feedback
func (d *Dao) AddFeedBack(c context.Context, l *model.Log) (err error) {
var (
tpB = make([]byte, 8)
key = exKey(l.Mid, int64(l.Time), l.IP)
ctx, cancel = context.WithTimeout(c, time.Duration(d.c.HBase.WriteTimeout))
)
defer cancel()
binary.BigEndian.PutUint64(tpB, uint64(l.Type))
values := map[string]map[string][]byte{familyEcpt: {columntp: tpB}}
if _, err = d.hbase.PutStr(ctx, tableSecure, key, values); err != nil {
log.Error("hbase.Put error(%v)", err)
}
return
}
// ExceptionLoc get exception loc.
func (d *Dao) ExceptionLoc(c context.Context, mid int64) (eps []*model.Expection, err error) {
var (
scanner hrpc.Scanner
result *hrpc.Result
ctx, cancel = context.WithTimeout(c, time.Duration(d.c.HBase.ReadTimeout))
)
defer cancel()
scanner, err = d.hbase.ScanRangeStr(ctx, tableSecure, exStartkey(mid), exStopKey(mid))
if err != nil {
log.Error("d.hbase.ScanRangeStr error(%v)", err)
return
}
for {
result, err = scanner.Next()
if err != nil {
if err == io.EOF {
err = nil
}
return
}
ep := new(model.Expection)
for _, c := range result.Cells {
if c != nil && bytes.Equal(c.Family, familyEcptB) {
switch string(c.Qualifier) {
case columnts:
ep.Time = xtime.Time(binary.BigEndian.Uint64(c.Value))
case columntp:
ep.FeedBack = int8(binary.BigEndian.Uint64(c.Value))
case columnip:
ep.IP = binary.BigEndian.Uint64(c.Value)
}
}
}
eps = append(eps, ep)
}
}

View File

@@ -0,0 +1,66 @@
package dao
import (
"context"
"testing"
"go-common/app/service/main/secure/model"
xtime "go-common/library/time"
. "github.com/smartystreets/goconvey/convey"
)
func TestAddLocs(t *testing.T) {
Convey("TestAddLocs", t, func() {
err := d.AddLocs(context.TODO(), 2, 3, 11)
d.AddLocs(context.TODO(), 2, 4, 12)
d.AddLocs(context.TODO(), 2, 4, 13)
d.AddLocs(context.TODO(), 2, 4, 14)
d.AddLocs(context.TODO(), 2, 3, 15)
So(err, ShouldBeNil)
})
}
func TestLocs(t *testing.T) {
Convey("TestLocs", t, func() {
locs, err := d.Locs(context.TODO(), 2)
So(err, ShouldBeNil)
So(locs, ShouldNotBeNil)
})
}
func TestAddEcpt(t *testing.T) {
Convey("TestAddEcpt", t, func() {
err := d.AddException(context.TODO(), &model.Log{Mid: 2, Time: xtime.Time(1111), IP: 222, LocationID: 3, Location: "aa"})
So(err, ShouldBeNil)
err = d.AddException(context.TODO(), &model.Log{Mid: 2, Time: xtime.Time(1311), IP: 222, LocationID: 3, Location: "aa"})
So(err, ShouldBeNil)
err = d.AddException(context.TODO(), &model.Log{Mid: 2333, Time: xtime.Time(1111), IP: 222, LocationID: 3, Location: "aa"})
So(err, ShouldBeNil)
})
}
func TestAddFeedBack(t *testing.T) {
Convey("TestAddFeedBack", t, func() {
err := d.AddFeedBack(context.TODO(), &model.Log{Mid: 2, Time: xtime.Time(1111), IP: 222, Type: 2, LocationID: 3, Location: "aa"})
if err != nil {
t.Errorf("test hbase add err %v", err)
}
})
}
func TestExcep(t *testing.T) {
Convey("TestExcep", t, func() {
locs, err := d.ExceptionLoc(context.TODO(), 2)
if err != nil {
t.Errorf("test hbase add err %v", err)
} else {
for _, l := range locs {
t.Logf("locs %v", l)
}
}
})
}

View File

@@ -0,0 +1,29 @@
package dao
import (
"context"
"net/url"
"strconv"
"go-common/library/log"
)
const (
_doubleCheckURL = "http://passport.bilibili.co/intranet/acc/security/mid"
)
// DoubleCheck notify passport to remove login.
func (d *Dao) DoubleCheck(c context.Context, mid int64) (err error) {
params := url.Values{}
params.Set("mids", strconv.FormatInt(mid, 10))
params.Set("desc", "异地风险,系统导入")
params.Set("operator", "异地系统判断")
var res struct {
Code int `json:"code"`
}
if err = d.httpClient.Post(c, _doubleCheckURL, "", params, &res); err != nil {
log.Error("d.Doublecheck err(%v)", err)
}
log.Info("d.DoubleCheck mid %d ", mid)
return
}

View File

@@ -0,0 +1,17 @@
package dao
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestDoubleCheck(t *testing.T) {
Convey("TestDoubleCheck", t, func() {
err := d.DoubleCheck(context.TODO(), 1)
if err != nil {
t.Errorf("test DoubleCheck err %v", err)
}
})
}

View File

@@ -0,0 +1,56 @@
package dao
import (
"context"
"strconv"
"go-common/app/service/main/secure/model"
gmc "go-common/library/cache/memcache"
"go-common/library/log"
)
const (
_prefixLocs = "locs_"
)
func locsKey(mid int64) string {
return _prefixLocs + strconv.FormatInt(mid, 10)
}
func (d *Dao) pingMC(c context.Context) (err error) {
conn := d.mc.Get(c)
if err = conn.Set(&gmc.Item{Key: "ping", Value: []byte{1}, Expiration: d.locsExpire}); err != nil {
log.Error("conn.Store(set, ping, 1) error(%v)", err)
}
conn.Close()
return
}
// AddLocsCache add login locs count to cache.
func (d *Dao) AddLocsCache(c context.Context, mid int64, locs *model.Locs) (err error) {
item := &gmc.Item{Key: locsKey(mid), Object: locs, Expiration: d.locsExpire, Flags: gmc.FlagProtobuf}
conn := d.mc.Get(c)
if err = conn.Set(item); err != nil {
log.Error("AddLocs err(%v)", err)
}
conn.Close()
return
}
// LocsCache get login locs count.
func (d *Dao) LocsCache(c context.Context, mid int64) (locs map[int64]int64, err error) {
conn := d.mc.Get(c)
defer conn.Close()
item, err := conn.Get(locsKey(mid))
if err != nil {
if err == gmc.ErrNotFound {
err = nil
}
return
}
loc := &model.Locs{}
if err = conn.Scan(item, loc); err != nil {
log.Error("Locs err(%v)", err)
}
locs = loc.LocsCount
return
}

View File

@@ -0,0 +1,72 @@
package dao
import (
"context"
"reflect"
"testing"
"go-common/app/service/main/secure/model"
"go-common/library/cache/memcache"
"github.com/bouk/monkey"
. "github.com/smartystreets/goconvey/convey"
)
func TestAddLocsCache(t *testing.T) {
Convey("TestAddLocsCache", t, func() {
err := d.AddLocsCache(context.TODO(), 3, &model.Locs{LocsCount: map[int64]int64{3: 2, 4: 3}})
So(err, ShouldBeNil)
})
Convey("TestAddLocsCacheErr", t, func() {
connGuard := monkey.PatchInstanceMethod(reflect.TypeOf(d.mc), "Get", func(_ *memcache.Pool, _ context.Context) memcache.Conn {
return memcache.MockWith(memcache.ErrItemObject)
})
defer connGuard.Unpatch()
err := d.AddLocsCache(context.TODO(), 3, &model.Locs{LocsCount: map[int64]int64{3: 2, 4: 3}})
So(err, ShouldEqual, memcache.ErrItemObject)
})
}
func TestLocsCache(t *testing.T) {
Convey("TestGetLocsCache", t, func() {
locs, err := d.LocsCache(context.TODO(), 3)
So(err, ShouldBeNil)
So(locs, ShouldNotBeNil)
})
Convey("TestGetLocsCacheGetErr", t, func() {
connGuard := monkey.PatchInstanceMethod(reflect.TypeOf(d.mc), "Get", func(_ *memcache.Pool, _ context.Context) memcache.Conn {
return memcache.MockWith(memcache.ErrNotFound)
})
defer connGuard.Unpatch()
locs, err := d.LocsCache(context.TODO(), 3)
So(err, ShouldBeNil)
So(locs, ShouldBeNil)
})
Convey("TestGetLocsCacheScanErr", t, func() {
connGuard := monkey.PatchInstanceMethod(reflect.TypeOf(d.mc), "Get", func(_ *memcache.Pool, _ context.Context) memcache.Conn {
return memcache.MockWith(memcache.ErrItemObject)
})
defer connGuard.Unpatch()
locs, err := d.LocsCache(context.TODO(), 3)
So(err, ShouldEqual, memcache.ErrItemObject)
So(locs, ShouldBeNil)
})
}
func TestMcPing(t *testing.T) {
Convey("TestMcPing", t, func() {
err := d.pingMC(context.Background())
So(err, ShouldBeNil)
})
Convey("TestMcPingErr", t, func() {
connGuard := monkey.PatchInstanceMethod(reflect.TypeOf(d.mc), "Get", func(_ *memcache.Pool, _ context.Context) memcache.Conn {
return memcache.MockWith(memcache.ErrConnClosed)
})
defer connGuard.Unpatch()
err := d.pingMC(context.Background())
So(err, ShouldNotBeNil)
So(err, ShouldEqual, memcache.ErrConnClosed)
})
}

View File

@@ -0,0 +1,225 @@
package dao
import (
"context"
"encoding/json"
"fmt"
"strconv"
"time"
model "go-common/app/service/main/secure/model"
"go-common/library/cache/redis"
"go-common/library/log"
)
const (
_prefixMsg = "m_"
_prefixUnNotify = "d_%d%d_%d"
_prefixCount = "c_%d%d_%d"
_prefixChangePWD = "cpwd_%d"
_prefixDoublecheck = "dc_%d"
_expire = 24 * 3600
_expirePWD = 30 * 24 * 3600
)
func doubleCheckKey(mid int64) string {
return fmt.Sprintf(_prefixDoublecheck, mid)
}
func changePWDKey(mid int64) string {
return fmt.Sprintf(_prefixChangePWD, mid)
}
func msgKey(mid int64) string {
return _prefixMsg + strconv.FormatInt(mid, 10)
}
func unnotifyKey(mid int64) string {
t := time.Now()
return fmt.Sprintf(_prefixUnNotify, t.Month(), t.Day(), mid)
}
func countKey(mid int64) string {
t := time.Now()
return fmt.Sprintf(_prefixCount, t.Month(), t.Day(), mid)
}
// AddExpectionMsg add user login expection msg.
func (d *Dao) AddExpectionMsg(c context.Context, l *model.Log) (err error) {
var (
conn = d.redis.Get(c)
bs []byte
key = msgKey(l.Mid)
)
defer conn.Close()
if bs, err = json.Marshal(l); err != nil {
log.Error("json.Marshal(%v) err(%v)", l, err)
return
}
if _, err = conn.Do("SETEX", key, d.expire, bs); err != nil {
log.Error("conn.Set msg:%v err(%v)", l, err)
}
return
}
// ExpectionMsg get user expection msg.
func (d *Dao) ExpectionMsg(c context.Context, mid int64) (msg *model.Log, err error) {
var (
conn = d.redis.Get(c)
bs []byte
)
defer conn.Close()
if bs, err = redis.Bytes(conn.Do("GET", msgKey(mid))); err != nil {
if err == redis.ErrNil {
err = nil
return
}
log.Error("conn.GET(mid %d) ,err(%v)", mid, err)
return
}
msg = &model.Log{}
if err = json.Unmarshal(bs, msg); err != nil {
log.Error("json.Unmarshal err(%v)", err)
}
return
}
// AddUnNotify user unnotiry uuid.
func (d *Dao) AddUnNotify(c context.Context, mid int64, uuid string) (err error) {
var (
conn = d.redis.Get(c)
key = unnotifyKey(mid)
)
defer conn.Close()
if err = conn.Send("SADD", key, uuid); err != nil {
log.Error("conn.SADD mid:%d err(%v)", mid, err)
return
}
if err = conn.Send("EXPIRE", key, _expire); err != nil {
log.Error("EXPIRE key :%d err %d", key, err)
return
}
conn.Flush()
for i := 0; i < 2; i++ {
if _, err = conn.Receive(); err != nil {
log.Error("conn.Recive err %v", err)
return
}
}
return
}
// DelUnNotify del user unnotify record.
func (d *Dao) DelUnNotify(c context.Context, mid int64) (err error) {
conn := d.redis.Get(c)
if _, err = conn.Do("DEL", unnotifyKey(mid)); err != nil {
log.Error("conn.DEL mid:%d err:%v", mid, err)
}
conn.Close()
return
}
// UnNotify check if not send notify to user of uuid deveice.
func (d *Dao) UnNotify(c context.Context, mid int64, uuid string) (b bool, err error) {
conn := d.redis.Get(c)
if b, err = redis.Bool(conn.Do("SISMEMBER", unnotifyKey(mid), uuid)); err != nil {
if err == redis.ErrNil {
err = nil
}
log.Error("conn.SISMEMBER (mid:%d) ERR(%v)", mid, err)
}
conn.Close()
return
}
// Count get user close notify count.
func (d *Dao) Count(c context.Context, mid int64, uuid string) (count int64, err error) {
conn := d.redis.Get(c)
if count, err = redis.Int64(conn.Do("HGET", countKey(mid), uuid)); err != nil {
if err == redis.ErrNil {
err = nil
}
log.Error("conn.GET mid:%d err(%v)", mid, err)
}
conn.Close()
return
}
// AddCount add user unnotify count daily.
func (d *Dao) AddCount(c context.Context, mid int64, uuid string) (err error) {
conn := d.redis.Get(c)
defer conn.Close()
if err = conn.Send("HINCRBY", countKey(mid), uuid, 1); err != nil {
log.Error("conn.INCR mid:%d err:%v", mid, err)
return
}
if err = conn.Send("EXPIRE", countKey(mid), _expire); err != nil {
log.Error("conn.EXPIRE mid:%d err:%v", mid, err)
return
}
conn.Flush()
for i := 0; i < 2; i++ {
if _, err1 := conn.Receive(); err1 != nil {
log.Error("conn.Receive err(%v)", err1)
return
}
}
return
}
// AddChangePWDRecord set user change passwd record to cache.
func (d *Dao) AddChangePWDRecord(c context.Context, mid int64) (err error) {
conn := d.redis.Get(c)
if _, err = conn.Do("SETEX", changePWDKey(mid), _expirePWD, 1); err != nil {
log.Error("d.ChangePWDRecord(mid %d) err(%v)", mid, err)
}
conn.Close()
return
}
// ChangePWDRecord check if user had change pwd recently one month.
func (d *Dao) ChangePWDRecord(c context.Context, mid int64) (b bool, err error) {
conn := d.redis.Get(c)
defer conn.Close()
if b, err = redis.Bool(conn.Do("GET", changePWDKey(mid))); err != nil {
if err == redis.ErrNil {
err = nil
return
}
log.Error("d.ChangePWDRecord err(%v)", err)
}
return
}
// DelCount del count
// for testing clear data.
func (d *Dao) DelCount(c context.Context, mid int64) (err error) {
conn := d.redis.Get(c)
defer conn.Close()
_, err = conn.Do("DEL", countKey(mid))
return
}
// AddDCheckCache add double check cache.
func (d *Dao) AddDCheckCache(c context.Context, mid int64) (err error) {
conn := d.redis.Get(c)
if _, err = conn.Do("SETEX", doubleCheckKey(mid), d.doubleCheckExpire, 1); err != nil {
log.Error("d.AddDCheckCache(mid %d) err(%v)", mid, err)
}
conn.Close()
return
}
// DCheckCache check if user had notify by double check.
func (d *Dao) DCheckCache(c context.Context, mid int64) (b bool, err error) {
conn := d.redis.Get(c)
defer conn.Close()
if b, err = redis.Bool(conn.Do("GET", doubleCheckKey(mid))); err != nil {
if err == redis.ErrNil {
err = nil
return
}
log.Error("d.DCheckCache err(%v)", err)
}
return
}

View File

@@ -0,0 +1,168 @@
package dao
import (
"context"
"testing"
"time"
model "go-common/app/service/main/secure/model"
xtime "go-common/library/time"
"github.com/smartystreets/goconvey/convey"
)
func TestRedis(t *testing.T) {
convey.Convey("TestRedis", t, func() {
lput := &model.Log{
Mid: 2,
Location: "上海",
LocationID: 11,
Time: xtime.Time(time.Now().Unix()),
}
d.AddExpectionMsg(context.TODO(), lput)
lget, _ := d.ExpectionMsg(context.TODO(), 2)
convey.So(lget.LocationID, convey.ShouldEqual, lput.LocationID)
d.AddUnNotify(context.TODO(), 2, "1234")
b, _ := d.UnNotify(context.TODO(), 2, "1234")
convey.So(b, convey.ShouldBeTrue)
d.DelUnNotify(context.TODO(), 2)
b, _ = d.UnNotify(context.TODO(), 2, "1234")
convey.So(b, convey.ShouldBeFalse)
d.AddCount(context.TODO(), 2, "1234")
d.AddCount(context.TODO(), 2, "1234")
count, _ := d.Count(context.TODO(), 2, "1234")
convey.So(count, convey.ShouldEqual, 2)
d.DelCount(context.TODO(), 2)
count, _ = d.Count(context.TODO(), 2, "1234")
convey.So(count, convey.ShouldEqual, 0)
})
}
func TestDoubleCheckKey(t *testing.T) {
convey.Convey("doubleCheckKey", t, func() {
p1 := doubleCheckKey(0)
convey.So(p1, convey.ShouldNotBeNil)
})
}
func TestChangePWDKey(t *testing.T) {
convey.Convey("changePWDKey", t, func() {
p1 := changePWDKey(0)
convey.So(p1, convey.ShouldNotBeNil)
})
}
func TestMsgKey(t *testing.T) {
convey.Convey("msgKey", t, func() {
p1 := msgKey(0)
convey.So(p1, convey.ShouldNotBeNil)
})
}
func TestUnnotifyKey(t *testing.T) {
convey.Convey("unnotifyKey", t, func() {
p1 := unnotifyKey(0)
convey.So(p1, convey.ShouldNotBeNil)
})
}
func TestCountKey(t *testing.T) {
convey.Convey("countKey", t, func() {
p1 := countKey(0)
convey.So(p1, convey.ShouldNotBeNil)
})
}
func TestDaoAddExpectionMsg(t *testing.T) {
var mid int64 = 7593623
convey.Convey("AddExpectionMsg", t, func() {
l := &model.Log{Mid: mid}
err := d.AddExpectionMsg(context.TODO(), l)
convey.So(err, convey.ShouldBeNil)
})
convey.Convey("ExpectionMsg", t, func() {
msg, err := d.ExpectionMsg(context.TODO(), mid)
convey.So(err, convey.ShouldBeNil)
convey.So(msg, convey.ShouldNotBeNil)
})
}
func TestDaoAddUnNotify(t *testing.T) {
convey.Convey("AddUnNotify", t, func() {
err := d.AddUnNotify(context.TODO(), 0, "")
convey.So(err, convey.ShouldBeNil)
})
}
func TestDaoDelUnNotify(t *testing.T) {
convey.Convey("DelUnNotify", t, func() {
err := d.DelUnNotify(context.TODO(), 0)
convey.So(err, convey.ShouldBeNil)
})
}
func TestDaoUnNotify(t *testing.T) {
convey.Convey("UnNotify", t, func() {
b, err := d.UnNotify(context.TODO(), 0, "")
convey.So(err, convey.ShouldBeNil)
convey.So(b, convey.ShouldNotBeNil)
})
}
func TestDaoCount(t *testing.T) {
convey.Convey("Count", t, func() {
count, err := d.Count(context.TODO(), 0, "")
convey.So(err, convey.ShouldBeNil)
convey.So(count, convey.ShouldNotBeNil)
})
}
func TestDaoAddCount(t *testing.T) {
convey.Convey("AddCount", t, func() {
err := d.AddCount(context.TODO(), 0, "")
convey.So(err, convey.ShouldBeNil)
})
}
func TestDaoAddChangePWDRecord(t *testing.T) {
convey.Convey("AddChangePWDRecord", t, func() {
err := d.AddChangePWDRecord(context.TODO(), 0)
convey.So(err, convey.ShouldBeNil)
})
}
func TestDaoChangePWDRecord(t *testing.T) {
convey.Convey("ChangePWDRecord", t, func() {
b, err := d.ChangePWDRecord(context.TODO(), 0)
convey.So(err, convey.ShouldBeNil)
convey.So(b, convey.ShouldNotBeNil)
})
}
func TestDaoDelCount(t *testing.T) {
convey.Convey("DelCount", t, func() {
err := d.DelCount(context.TODO(), 0)
convey.So(err, convey.ShouldBeNil)
})
}
func TestDaoAddDCheckCache(t *testing.T) {
convey.Convey("AddDCheckCache", t, func() {
err := d.AddDCheckCache(context.TODO(), 0)
convey.So(err, convey.ShouldBeNil)
})
}
func TestDaoDCheckCache(t *testing.T) {
convey.Convey("DCheckCache", t, func() {
b, err := d.DCheckCache(context.TODO(), 0)
convey.So(err, convey.ShouldBeNil)
convey.So(b, convey.ShouldNotBeNil)
})
}

View File

@@ -0,0 +1,37 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"http.go",
"remotelogin.go",
],
importpath = "go-common/app/service/main/secure/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/secure/conf:go_default_library",
"//app/service/main/secure/service:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/verify:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,64 @@
package http
import (
"net/http"
"go-common/app/service/main/secure/conf"
"go-common/app/service/main/secure/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/http/blademaster/middleware/verify"
)
var (
rSrv *service.Service
verSvc *verify.Verify
)
// Init init http service
func Init(s *service.Service) {
initService(s)
e := bm.DefaultServer(conf.Conf.BM)
innerRouter(e)
if err := e.Start(); err != nil {
log.Error("e.Start() error(%v)", err)
panic(err)
}
}
func initService(s *service.Service) {
rSrv = s
verSvc = verify.New(conf.Conf.Verify)
}
// innerRouter init local router api path.
func innerRouter(e *bm.Engine) {
e.Ping(ping)
e.Register(register)
group := e.Group("/x/internal/secure", verSvc.Verify)
{
group.GET("/loc", getLoc)
group.POST("/often/check", oftenCheck)
expect := group.Group("/expect")
{
expect.GET("/status", status)
expect.POST("/close", closeNotify)
expect.GET("/loc", loc)
expect.POST("/feedback", feedback)
expect.POST("/test", addlog)
}
}
}
// ping check server ok.
func ping(c *bm.Context) {
if err := rSrv.Ping(c); err != nil {
log.Error("ping error(%+v)", err)
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}
// register check server ok.
func register(c *bm.Context) {
c.JSON(map[string]interface{}{}, nil)
}

View File

@@ -0,0 +1,120 @@
package http
import (
"strconv"
"go-common/library/ecode"
bm "go-common/library/net/http/blademaster"
)
func addlog(c *bm.Context) {
res := c.Request
mid := res.Form.Get("mid")
ip := res.Form.Get("ip")
c.JSON(nil, rSrv.AddLog(c, mid, ip))
}
func getLoc(c *bm.Context) {
var (
mid int64
params = c.Request.Form
midStr = params.Get("mid")
)
mid, err := strconv.ParseInt(midStr, 10, 64)
if err != nil || mid < 0 {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(rSrv.GetLoc(c, mid))
}
func status(c *bm.Context) {
var (
mid int64
params = c.Request.Form
midStr = params.Get("mid")
uuid = params.Get("uuid")
)
mid, err := strconv.ParseInt(midStr, 10, 64)
if err != nil || mid < 0 {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(rSrv.Status(c, mid, uuid))
}
func closeNotify(c *bm.Context) {
var (
mid int64
params = c.Request.Form
midStr = params.Get("mid")
uuid = params.Get("uuid")
)
mid, err := strconv.ParseInt(midStr, 10, 64)
if err != nil || mid < 0 {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(nil, rSrv.CloseNotify(c, mid, uuid))
}
func loc(c *bm.Context) {
var (
mid int64
params = c.Request.Form
midStr = params.Get("mid")
)
mid, err := strconv.ParseInt(midStr, 10, 64)
if err != nil || mid < 0 {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(rSrv.ExpectionLoc(c, mid))
}
func feedback(c *bm.Context) {
var (
mid int64
params = c.Request.Form
midStr = params.Get("mid")
ip = params.Get("ip")
tsStr = params.Get("logintime")
tpStr = params.Get("tp")
)
mid, err := strconv.ParseInt(midStr, 10, 64)
if err != nil || mid < 0 {
c.JSON(nil, ecode.RequestErr)
return
}
tp, err := strconv.ParseInt(tpStr, 10, 8)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
ts, err := strconv.ParseInt(tsStr, 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(nil, rSrv.AddFeedBack(c, mid, ts, int8(tp), ip))
}
func oftenCheck(c *bm.Context) {
var (
mid int64
params = c.Request.Form
midStr = params.Get("mid")
ip = params.Get("ip")
)
mid, err := strconv.ParseInt(midStr, 10, 64)
if err != nil || mid <= 0 {
c.JSON(nil, ecode.RequestErr)
return
}
result, err := rSrv.OftenCheck(c, mid, ip)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(result, nil)
}

View File

@@ -0,0 +1,54 @@
load(
"@io_bazel_rules_go//proto:def.bzl",
"go_proto_library",
)
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["log.go"],
embed = [":model_go_proto"],
importpath = "go-common/app/service/main/secure/model",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/time:go_default_library",
"@com_github_gogo_protobuf//gogoproto:go_default_library",
"@com_github_golang_protobuf//proto:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
proto_library(
name = "model_proto",
srcs = ["locs.proto"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = ["@gogo_special_proto//github.com/gogo/protobuf/gogoproto"],
)
go_proto_library(
name = "model_go_proto",
compilers = ["@io_bazel_rules_go//proto:gogofast_proto"],
importpath = "go-common/app/service/main/secure/model",
proto = ":model_proto",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = ["@com_github_gogo_protobuf//gogoproto:go_default_library"],
)

View File

@@ -0,0 +1,399 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: locs.proto
/*
Package model is a generated protocol buffer package.
It is generated from these files:
locs.proto
It has these top-level messages:
Locs
*/
package model
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import _ "github.com/gogo/protobuf/gogoproto"
import io "io"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Locs struct {
LocsCount map[int64]int64 `protobuf:"bytes,1,rep,name=locsCount" json:"locsCount,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"varint,2,opt,name=value,proto3"`
}
func (m *Locs) Reset() { *m = Locs{} }
func (m *Locs) String() string { return proto.CompactTextString(m) }
func (*Locs) ProtoMessage() {}
func (*Locs) Descriptor() ([]byte, []int) { return fileDescriptorLocs, []int{0} }
func init() {
proto.RegisterType((*Locs)(nil), "model.Locs")
}
func (m *Locs) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *Locs) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if len(m.LocsCount) > 0 {
for k, _ := range m.LocsCount {
dAtA[i] = 0xa
i++
v := m.LocsCount[k]
mapSize := 1 + sovLocs(uint64(k)) + 1 + sovLocs(uint64(v))
i = encodeVarintLocs(dAtA, i, uint64(mapSize))
dAtA[i] = 0x8
i++
i = encodeVarintLocs(dAtA, i, uint64(k))
dAtA[i] = 0x10
i++
i = encodeVarintLocs(dAtA, i, uint64(v))
}
}
return i, nil
}
func encodeFixed64Locs(dAtA []byte, offset int, v uint64) int {
dAtA[offset] = uint8(v)
dAtA[offset+1] = uint8(v >> 8)
dAtA[offset+2] = uint8(v >> 16)
dAtA[offset+3] = uint8(v >> 24)
dAtA[offset+4] = uint8(v >> 32)
dAtA[offset+5] = uint8(v >> 40)
dAtA[offset+6] = uint8(v >> 48)
dAtA[offset+7] = uint8(v >> 56)
return offset + 8
}
func encodeFixed32Locs(dAtA []byte, offset int, v uint32) int {
dAtA[offset] = uint8(v)
dAtA[offset+1] = uint8(v >> 8)
dAtA[offset+2] = uint8(v >> 16)
dAtA[offset+3] = uint8(v >> 24)
return offset + 4
}
func encodeVarintLocs(dAtA []byte, offset int, v uint64) int {
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return offset + 1
}
func (m *Locs) Size() (n int) {
var l int
_ = l
if len(m.LocsCount) > 0 {
for k, v := range m.LocsCount {
_ = k
_ = v
mapEntrySize := 1 + sovLocs(uint64(k)) + 1 + sovLocs(uint64(v))
n += mapEntrySize + 1 + sovLocs(uint64(mapEntrySize))
}
}
return n
}
func sovLocs(x uint64) (n int) {
for {
n++
x >>= 7
if x == 0 {
break
}
}
return n
}
func sozLocs(x uint64) (n int) {
return sovLocs(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *Locs) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowLocs
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: Locs: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Locs: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field LocsCount", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowLocs
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthLocs
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.LocsCount == nil {
m.LocsCount = make(map[int64]int64)
}
var mapkey int64
var mapvalue int64
for iNdEx < postIndex {
entryPreIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowLocs
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
if fieldNum == 1 {
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowLocs
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
mapkey |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
} else if fieldNum == 2 {
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowLocs
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
mapvalue |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
} else {
iNdEx = entryPreIndex
skippy, err := skipLocs(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthLocs
}
if (iNdEx + skippy) > postIndex {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
m.LocsCount[mapkey] = mapvalue
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipLocs(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthLocs
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipLocs(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowLocs
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowLocs
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
return iNdEx, nil
case 1:
iNdEx += 8
return iNdEx, nil
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowLocs
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
iNdEx += length
if length < 0 {
return 0, ErrInvalidLengthLocs
}
return iNdEx, nil
case 3:
for {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowLocs
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
innerWire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
innerWireType := int(innerWire & 0x7)
if innerWireType == 4 {
break
}
next, err := skipLocs(dAtA[start:])
if err != nil {
return 0, err
}
iNdEx = start + next
}
return iNdEx, nil
case 4:
return iNdEx, nil
case 5:
iNdEx += 4
return iNdEx, nil
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
}
panic("unreachable")
}
var (
ErrInvalidLengthLocs = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowLocs = fmt.Errorf("proto: integer overflow")
)
func init() { proto.RegisterFile("locs.proto", fileDescriptorLocs) }
var fileDescriptorLocs = []byte{
// 191 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0xca, 0xc9, 0x4f, 0x2e,
0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0xcd, 0xcd, 0x4f, 0x49, 0xcd, 0x91, 0xd2, 0x4d,
0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xcf, 0x4f, 0xcf, 0xd7, 0x07,
0xcb, 0x26, 0x95, 0xa6, 0x81, 0x79, 0x60, 0x0e, 0x98, 0x05, 0xd1, 0xa5, 0x54, 0xc7, 0xc5, 0xe2,
0x93, 0x9f, 0x5c, 0x2c, 0x64, 0xc1, 0xc5, 0x09, 0x32, 0xcb, 0x39, 0xbf, 0x34, 0xaf, 0x44, 0x82,
0x51, 0x81, 0x59, 0x83, 0xdb, 0x48, 0x4a, 0x0f, 0x6c, 0xa2, 0x1e, 0x48, 0x1e, 0x4c, 0x80, 0x25,
0x5d, 0xf3, 0x4a, 0x8a, 0x2a, 0x83, 0x10, 0x8a, 0xa5, 0x6c, 0xb8, 0xf8, 0x50, 0x25, 0x85, 0x04,
0xb8, 0x98, 0xb3, 0x53, 0x2b, 0x25, 0x18, 0x15, 0x18, 0x35, 0x98, 0x83, 0x40, 0x4c, 0x21, 0x11,
0x2e, 0xd6, 0xb2, 0xc4, 0x9c, 0xd2, 0x54, 0x09, 0x26, 0xb0, 0x18, 0x84, 0x63, 0xc5, 0x64, 0xc1,
0xe8, 0x24, 0x71, 0xe2, 0xa1, 0x1c, 0xc3, 0x85, 0x87, 0x72, 0x0c, 0x27, 0x1e, 0xc9, 0x31, 0x5e,
0x78, 0x24, 0xc7, 0xf8, 0xe0, 0x91, 0x1c, 0xe3, 0x8c, 0xc7, 0x72, 0x0c, 0x49, 0x6c, 0x60, 0x07,
0x1a, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x3a, 0x9f, 0x95, 0x78, 0xe4, 0x00, 0x00, 0x00,
}

View File

@@ -0,0 +1,15 @@
syntax = "proto3";
package model;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option (gogoproto.goproto_enum_prefix_all) = false;
option (gogoproto.goproto_getters_all) = false;
option (gogoproto.unmarshaler_all) = true;
option (gogoproto.marshaler_all) = true;
option (gogoproto.sizer_all) = true;
message Locs {
map<int64,int64> locsCount = 1;
}

View File

@@ -0,0 +1,68 @@
package model
import (
"encoding/json"
"go-common/library/time"
)
// ArgSecure arg secure.
type ArgSecure struct {
Mid int64 `json:"mid,omitempty"`
UUID string `json:"uuid,omitempty"`
}
// ArgFeedBack arg feedback.
type ArgFeedBack struct {
Mid int64 `json:"mid,omitempty"`
UUID string `json:"uuid,omitempty"`
IP string `json:"ip,omitempty"`
Type int8 `json:"type,omitempty"`
Ts int64 `json:"ts"`
}
// Log define user login log.
type Log struct {
Mid int64 `json:"mid,omitempty"`
IP uint32 `json:"loginip"`
Location string `json:"location"`
LocationID int64 `json:"location_id,omitempty"`
Time time.Time `json:"timestamp,omitempty"`
Type int8 `json:"type,omitempty"`
}
// Msg is user login status msg.
type Msg struct {
Notify bool `json:"notify"`
Log *Log `json:"log"`
}
// Message is databus message.
type Message struct {
Action string `json:"action"`
Table string `json:"table"`
New json.RawMessage `json:"new"`
Old json.RawMessage `json:"old"`
}
// Expection is user expection record.
type Expection struct {
IP uint64 `json:"ip"`
Time time.Time `json:"time"`
FeedBack int8 `json:"feedback"`
}
// PWDlog is user change password log.
type PWDlog struct {
Mid int64 `json:"mid"`
}
// Record user login record.
type Record struct {
LocID int64 `json:"locid"`
Count int64 `json:"count"`
}
// Often is user often use ipaddr
type Often struct {
Result bool `json:"result"`
}

View File

@@ -0,0 +1,40 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = ["secure.go"],
importpath = "go-common/app/service/main/secure/rpc/client",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/secure/model:go_default_library",
"//library/net/rpc:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["secure_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = ["//app/service/main/secure/model:go_default_library"],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,58 @@
package secure
import (
"context"
model "go-common/app/service/main/secure/model"
"go-common/library/net/rpc"
)
const (
_status = "RPC.Status"
_expect = "RPC.ExpectionLoc"
_addFeedback = "RPC.AddFeedBack"
_closeNotify = "RPC.CloseNotify"
)
const (
_appid = "account.service.secure"
)
var (
_noRes = &struct{}{}
)
// Service rpc service.
type Service struct {
client *rpc.Client2
}
// New new rpc service.
func New(c *rpc.ClientConfig) (s *Service) {
s = &Service{}
s.client = rpc.NewDiscoveryCli(_appid, c)
return
}
// Status get the ip info.
func (s *Service) Status(c context.Context, arg *model.ArgSecure) (res *model.Msg, err error) {
res = new(model.Msg)
err = s.client.Call(c, _status, arg, &res)
return
}
// CloseNotify clsoe notify.
func (s *Service) CloseNotify(c context.Context, arg *model.ArgSecure) (err error) {
return s.client.Call(c, _closeNotify, arg, &_noRes)
}
// AddFeedBack add expection feedback.
func (s *Service) AddFeedBack(c context.Context, arg *model.ArgFeedBack) (err error) {
return s.client.Call(c, _addFeedback, arg, &_noRes)
}
// ExpectionLoc get expection loc.
func (s *Service) ExpectionLoc(c context.Context, arg *model.ArgSecure) (res []*model.Expection, err error) {
err = s.client.Call(c, _expect, arg, &res)
return
}

View File

@@ -0,0 +1,35 @@
package secure
import (
"context"
"testing"
"time"
model "go-common/app/service/main/secure/model"
)
var s *Service
func TestSecure(t *testing.T) {
s = New(nil)
time.Sleep(1000 * time.Second)
testStatus(t)
testExpectionLoc(t)
}
// TestStatus test status rpc.
func testStatus(t *testing.T) {
if res, err := s.Status(context.TODO(), &model.ArgSecure{Mid: 1, UUID: "2"}); err != nil {
t.Errorf("Service: Status err: %v", err)
} else {
t.Logf("Service: Status res: %+v", res)
}
}
func testExpectionLoc(t *testing.T) {
if res, err := s.ExpectionLoc(context.TODO(), &model.ArgSecure{Mid: 1, UUID: "2"}); err != nil {
t.Errorf("Service : Expection err:%v", err)
} else {
t.Logf("Service: Status res: %+v", res)
}
}

View File

@@ -0,0 +1,33 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = ["rpc.go"],
importpath = "go-common/app/service/main/secure/rpc/server",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/secure/conf:go_default_library",
"//app/service/main/secure/model:go_default_library",
"//app/service/main/secure/service:go_default_library",
"//library/net/rpc:go_default_library",
"//library/net/rpc/context:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,56 @@
package rpc
import (
"go-common/app/service/main/secure/conf"
model "go-common/app/service/main/secure/model"
"go-common/app/service/main/secure/service"
"go-common/library/net/rpc"
"go-common/library/net/rpc/context"
)
// RPC rpc service.
type RPC struct {
s *service.Service
}
// New init rpc.
func New(c *conf.Config, s *service.Service) (svr *rpc.Server) {
r := &RPC{s: s}
svr = rpc.NewServer(c.RPCServer)
if err := svr.Register(r); err != nil {
panic(err)
}
return
}
// Ping check connection success.
func (r *RPC) Ping(c context.Context, arg *struct{}, res *struct{}) (err error) {
return
}
// Status rpc status.
func (r *RPC) Status(c context.Context, a *model.ArgSecure, res *model.Msg) (err error) {
var tmp *model.Msg
if tmp, err = r.s.Status(c, a.Mid, a.UUID); err == nil && tmp != nil {
*res = *tmp
}
return
}
// CloseNotify rpc close notify.
func (r *RPC) CloseNotify(c context.Context, arg *model.ArgSecure, res *struct{}) (err error) {
err = r.s.CloseNotify(c, arg.Mid, arg.UUID)
return
}
// AddFeedBack rpc add feedback.
func (r *RPC) AddFeedBack(c context.Context, arg *model.ArgFeedBack, res *struct{}) (err error) {
err = r.s.AddFeedBack(c, arg.Mid, arg.Ts, arg.Type, arg.IP)
return
}
// ExpectionLoc rpc expection loc list.
func (r *RPC) ExpectionLoc(c context.Context, arg *model.ArgSecure, res *[]*model.Expection) (err error) {
*res, err = r.s.ExpectionLoc(c, arg.Mid)
return
}

View File

@@ -0,0 +1,54 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"remotelogin.go",
"service.go",
],
importpath = "go-common/app/service/main/secure/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/location/model:go_default_library",
"//app/service/main/location/rpc/client:go_default_library",
"//app/service/main/secure/conf:go_default_library",
"//app/service/main/secure/dao:go_default_library",
"//app/service/main/secure/model:go_default_library",
"//library/log:go_default_library",
"//library/queue/databus:go_default_library",
"//library/time:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = ["remotelogin_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/secure/conf:go_default_library",
"//app/service/main/secure/model:go_default_library",
"//library/log:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,318 @@
package service
import (
"context"
"encoding/json"
"math/rand"
"sort"
"strconv"
"strings"
"time"
location "go-common/app/service/main/location/model"
"go-common/app/service/main/secure/model"
"go-common/library/log"
xtime "go-common/library/time"
)
var (
_serverOutIP = map[string]struct{}{
"183.131.11.57": {},
"58.220.29.45": {},
"58.220.29.46": {},
"58.220.29.47": {},
"121.43.189.63": {},
"58.220.29.48": {},
"192.73.241.22": {},
"58.220.29.41": {},
"122.228.103.138": {},
"120.41.32.13": {},
"59.47.225.6": {},
"222.73.196.16": {},
"222.73.196.17": {},
"222.73.196.18": {},
"222.73.196.19": {},
"222.73.196.20": {},
"222.73.196.21": {},
"222.73.196.22": {},
"222.73.196.23": {},
"222.73.196.24": {},
"222.73.196.25": {},
"222.73.196.26": {},
"222.73.196.27": {},
"222.73.196.28": {},
"222.73.196.29": {},
"222.73.196.30": {},
"121.46.231.65": {},
"121.46.231.66": {},
"121.46.231.67": {},
"121.46.231.68": {},
"121.46.231.69": {},
"121.46.231.70": {},
"116.211.6.85": {},
"116.211.6.86": {},
}
)
func (s *Service) changePWDRecord(c context.Context, msg []byte) (err error) {
l := &model.PWDlog{}
if err = json.Unmarshal(msg, l); err != nil {
log.Error("s.changePWDRecord err(%v)", err)
return
}
if msg, _ := s.dao.ExpectionMsg(c, l.Mid); msg != nil {
s.dao.AddChangePWDRecord(c, l.Mid)
}
return
}
func (s *Service) loginLog(c context.Context, action string, new []byte) (err error) {
var (
res *location.InfoComplete
ms = &model.Log{}
)
if err = json.Unmarshal(new, ms); err != nil {
log.Error("json.Unmarshal err(%v)", err)
return
}
switch action {
case "insert":
ipStr := inetNtoA(ms.IP)
if _, ok := _serverOutIP[ipStr]; ok {
return
}
if strings.HasPrefix(ipStr, "127") {
return
}
if res, err = s.getIPZone(c, ipStr); err != nil || res == nil {
return
}
if res.Country == "局域网" {
return
}
ms.LocationID = res.ZoneID[2]
ms.Location = res.Country + res.Province
s.checkExpectLogin(c, ms)
//_, err = s.dao.AddLoginLog(c, ms)
err = s.dao.AddLocs(c, ms.Mid, ms.LocationID, int64(ms.Time))
if err != nil {
return
}
case "default":
}
return
}
func (s *Service) getIPZone(c context.Context, ip string) (res *location.InfoComplete, err error) {
arg := &location.ArgIP{
IP: ip,
}
if res, err = s.locRPC.InfoComplete(c, arg); err != nil {
log.Error("s.locaRPC err(%v)", err)
}
return
}
// GetLoc get loc by mid
func (s *Service) GetLoc(c context.Context, mid int64) (res []int64, err error) {
rs, err := s.dao.Locs(c, mid)
if err != nil {
return
}
if len(rs) == 0 {
return
}
res = make([]int64, 0, len(rs))
for k := range rs {
res = append(res, k)
}
return
}
// Status get user expect login status.
func (s *Service) Status(c context.Context, mid int64, uuid string) (msg *model.Msg, err error) {
var (
count int64
unnotify, change bool
lg *model.Log
)
if lg, err = s.dao.ExpectionMsg(c, mid); err != nil {
return
}
if lg == nil {
return
}
msg = &model.Msg{
Log: lg,
Notify: true,
}
if unnotify, err = s.dao.UnNotify(c, mid, uuid); err != nil {
err = nil
return
}
if unnotify {
msg.Notify = false
return
}
if change, err = s.dao.ChangePWDRecord(c, mid); err != nil {
log.Error("s.dao.ChangePWDRecord err(%v)", err)
err = nil
return
}
if change {
msg.Notify = false
return
}
if count, err = s.dao.Count(c, mid, uuid); err != nil {
err = nil
return
}
if count >= s.c.Expect.CloseCount {
msg.Notify = false
return
}
if rand.Int63n(s.c.Expect.Rand) != 0 {
msg.Notify = false
}
return
}
// CloseNotify add unnotify of mid and uuid.
func (s *Service) CloseNotify(c context.Context, mid int64, uuid string) (err error) {
err = s.dao.AddUnNotify(c, mid, uuid)
if err != nil {
return
}
return s.dao.AddCount(c, mid, uuid)
}
func (s *Service) checkExpectLogin(c context.Context, l *model.Log) (err error) {
locs, err := s.commonLoc(c, l.Mid)
if err != nil {
log.Error("checkExpectLogin err(%v)", err)
return
}
// no common location.
if len(locs) < 3 {
return
}
// expection login.
expect := true
for _, loc := range locs {
if loc.LocID == l.LocationID {
expect = false
break
}
}
if expect {
if err = s.addExpectionLog(c, l); err != nil {
return
}
err = s.addExpectionMsg(c, l)
// del old unnotify record.
s.delUnNotify(c, l.Mid)
}
return
}
func (s *Service) addExpectionLog(c context.Context, l *model.Log) (err error) {
return s.dao.AddException(c, l)
}
func (s *Service) delUnNotify(c context.Context, mid int64) (err error) {
return s.dao.DelUnNotify(c, mid)
}
func (s *Service) addExpectionMsg(c context.Context, l *model.Log) (err error) {
return s.dao.AddExpectionMsg(c, l)
}
// AddFeedBack add user expection login feedback.
func (s *Service) AddFeedBack(c context.Context, mid, ts int64, tp int8, IP string) (err error) {
var res *location.InfoComplete
if res, err = s.getIPZone(c, IP); err != nil || res == nil {
return
}
l := &model.Log{
Location: res.Country + res.Province,
IP: inetAtoN(IP),
Mid: mid,
Type: tp,
Time: xtime.Time(ts),
}
return s.dao.AddFeedBack(c, l)
}
// ExpectionLoc get user expction login list.
func (s *Service) ExpectionLoc(c context.Context, mid int64) (res []*model.Expection, err error) {
return s.dao.ExceptionLoc(c, mid)
}
func (s *Service) commonLoc(c context.Context, mid int64) (rcs []*model.Record, err error) {
//locs, err := s.dao.CommonLoc(c, mid, now)
locs, _ := s.dao.LocsCache(c, mid)
if len(locs) == 0 {
// cache miss ,get from db.
locs, err = s.dao.Locs(c, mid)
if err != nil {
return
}
s.dao.AddLocsCache(c, mid, &model.Locs{LocsCount: locs})
}
if len(locs) >= int(s.c.Expect.DoubleCheck) {
if ok, _ := s.dao.DCheckCache(c, mid); ok {
return
}
if ok, _ := s.dao.ChangePWDRecord(c, mid); ok {
return
}
s.dao.DoubleCheck(c, mid)
s.dao.AddDCheckCache(c, mid)
}
for l, c := range locs {
if c > s.c.Expect.Count {
rc := &model.Record{LocID: l, Count: c}
rcs = append(rcs, rc)
}
}
sort.Slice(rcs, func(i, j int) bool { return rcs[i].Count > rcs[j].Count })
if len(rcs) > int(s.c.Expect.Top) {
rcs = rcs[:s.c.Expect.Top]
}
return
}
// AddLog for test.
func (s *Service) AddLog(c context.Context, mid, ips string) (err error) {
log := &model.Log{}
log.Mid, _ = strconv.ParseInt(mid, 10, 64)
log.IP = inetAtoN(ips)
log.Time = xtime.Time(time.Now().Unix())
bs, _ := json.Marshal(log)
err = s.loginLog(c, "insert", bs)
return
}
// OftenCheck check user often use ipaddress
func (s *Service) OftenCheck(c context.Context, mid int64, ip string) (often *model.Often, err error) {
var (
lip *location.InfoComplete
locs []*model.Record
)
often = &model.Often{}
if lip, err = s.getIPZone(c, ip); err != nil || lip == nil {
return
}
if locs, err = s.commonLoc(c, mid); err != nil {
log.Error("checkExpectLogin err(%v)", err)
return
}
log.Info("user common len:%d", len(locs))
for _, loc := range locs {
log.Info("user curr(%+v), common log:(%+v)", lip, loc)
if loc.LocID == lip.ZoneID[2] {
often.Result = true
break
}
}
return
}

View File

@@ -0,0 +1,159 @@
package service
import (
"context"
"flag"
"sync"
"testing"
"time"
"go-common/app/service/main/secure/conf"
model "go-common/app/service/main/secure/model"
"go-common/library/log"
. "github.com/smartystreets/goconvey/convey"
)
var (
once sync.Once
s *Service
ctx = context.Background()
)
func startService() {
initConf()
s = New(conf.Conf)
time.Sleep(time.Second * 2)
}
func initConf() {
flag.Set("conf", "../cmd/secure-service-test.toml")
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Log)
defer log.Close()
}
func (s *Service) initCache(mid int64, uuid string) {
s.delUnNotify(ctx, mid)
s.dao.DelCount(ctx, mid)
}
func TestLoginLog(t *testing.T) {
once.Do(startService)
commonlog1 := []byte(`{"id":79839245,"loginip":288673833,"mid":3,"server":"","timestamp":1498016443,"type":4}`)
commonlog2 := []byte(`{"id":79839245,"loginip":288673823,"mid":3,"server":"","timestamp":1498016444,"type":4}`)
commonlog3 := []byte(`{"id":79839245,"loginip":288673823,"mid":3,"server":"","timestamp":1498016445,"type":4}`)
commonlog4 := []byte(`{"id":79839245,"loginip":288673823,"mid":3,"server":"","timestamp":1498016446,"type":4}`)
commonlog5 := []byte(`{"id":79839245,"loginip":288673823,"mid":3,"server":"","timestamp":1498016447,"type":4}`)
err := s.loginLog(ctx, "insert", commonlog1)
if err != nil {
t.Errorf("err %v", err)
}
s.commonLoc(ctx, 3)
s.loginLog(ctx, "insert", commonlog2)
s.loginLog(ctx, "insert", commonlog3)
s.loginLog(ctx, "insert", commonlog4)
s.loginLog(ctx, "insert", commonlog5)
}
func TestCloseNotify(t *testing.T) {
once.Do(startService)
s.initCache(1, "1234")
s.CloseNotify(ctx, 1, "1234")
b, err := s.dao.UnNotify(ctx, 1, "1234")
if err != nil {
t.Error("s.dao.UnNotify err", err)
}
if !b {
t.Errorf("unnotify want true but get %v", b)
}
count, _ := s.dao.Count(ctx, 1, "1234")
if count != 1 {
t.Errorf("user close count want 1,but get %d", count)
}
}
func TestStatus(t *testing.T) {
once.Do(startService)
s.initCache(2, "abc")
commonlog := []byte(`{"id":79839246,"loginip":2886738232,"mid":2,"server":"","timestamp":1498016443,"type":4}`)
expectlog := []byte(`{"id":79839246,"loginip":3078818617,"mid":2,"server":"","timestamp":1498016443,"type":4}`)
for i := 0; i < 4; i++ {
s.loginLog(ctx, "insert", commonlog)
}
s.loginLog(ctx, "insert", expectlog)
res, err := s.Status(ctx, 2, "abc")
if err != nil || res == nil {
t.Fatalf("s.Status err %v ", err)
}
if !res.Notify {
t.Errorf("s.Status want notify true but get %v", res.Notify)
}
t.Logf("status notify %v ", res)
s.CloseNotify(ctx, 2, "abc")
res, err = s.Status(ctx, 2, "abc")
if err != nil || res == nil {
t.Fatalf("s.Status err %v ", err)
}
if res.Notify {
t.Errorf("s.Status want notify true but get %v", res.Notify)
}
if err != nil || res == nil {
t.Fatalf("s.Status err %v ", err)
}
if res.Notify {
t.Errorf("s.Status want notify false but get %v", res.Notify)
}
for i := 0; i < int(s.c.Expect.CloseCount); i++ {
s.dao.AddCount(ctx, 2, "1234")
}
res, err = s.Status(ctx, 2, "abcd")
if err != nil || res == nil {
t.Fatalf("s.Status err %v ", err)
}
if !res.Notify {
t.Errorf("s.Status want notify true but get %v", res.Notify)
}
}
func TestGetIP(t *testing.T) {
once.Do(startService)
res, err := s.getIPZone(ctx, "139.214.144.59")
if err != nil {
t.Errorf("getIPZone err(%v)", err)
}
t.Logf("res %v", res)
res, err = s.getIPZone(ctx, "218.27.198.190")
if err != nil {
t.Errorf("getIPZone err(%v)", err)
}
t.Logf("res %v", res)
}
func TestAddFeedBack(t *testing.T) {
once.Do(startService)
s.AddFeedBack(ctx, 1, 1111, 2, "172.16.33.54")
}
func TestAddExpectlogin(t *testing.T) {
once.Do(startService)
l := &model.Log{Mid: 1, Location: "shanghai", LocationID: 111}
s.addExpectionLog(ctx, l)
}
func TestCommonLoc(t *testing.T) {
once.Do(startService)
res, err := s.commonLoc(ctx, 4780461)
if err != nil {
t.Errorf("err %v", err)
}
t.Log(res)
for _, r := range res {
t.Logf("res %v", r)
}
}
func Test_OftenCheck(t *testing.T) {
Convey("not often ip", t, func() {
once.Do(startService)
res, err := s.OftenCheck(ctx, 4780461, "127.0.0.1")
So(err, ShouldEqual, nil)
So(res.Result, ShouldEqual, false)
})
}

View File

@@ -0,0 +1,126 @@
package service
import (
"context"
"encoding/json"
"net"
"strings"
"time"
location "go-common/app/service/main/location/rpc/client"
"go-common/app/service/main/secure/conf"
"go-common/app/service/main/secure/dao"
"go-common/app/service/main/secure/model"
"go-common/library/log"
"go-common/library/queue/databus"
)
const (
_loginLog = "aso_login_log"
_pwdLog = "aso_pwd_log"
_retry = 3
_retrySleep = time.Second * 1
)
// Service struct of service.
type Service struct {
c *conf.Config
dao *dao.Dao
ds *databus.Databus
locRPC *location.Service
}
// New create service instance and return.
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: dao.New(c),
ds: databus.New(c.DataBus),
locRPC: location.New(c.LocationRPC),
}
go s.subproc()
// go s.tableproc()
return
}
// func (s *Service) tableproc() {
// for {
// now := time.Now()
// ts := time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 0, 0, time.Local).Sub(time.Now())
// time.Sleep(ts)
// err := s.dao.CreateTable(context.TODO(), now.AddDate(0, 0, 1))
// fmt.Println("create table", err)
// log.Info("createtable err", err)
// err = s.dao.DropTable(context.TODO(), now.AddDate(0, 0, -8))
// log.Info("drop table err(%v)", err)
// time.Sleep(time.Hour)
// }
// }
func (s *Service) subproc() {
var err error
for {
res, ok := <-s.ds.Messages()
if !ok {
return
}
mu := &model.Message{}
if err = json.Unmarshal(res.Value, mu); err != nil {
log.Error("credit-job,json.Unmarshal (%v) error(%v)", string(res.Value), err)
continue
}
for i := 0; i < _retry; i++ {
switch {
case strings.HasPrefix(mu.Table, _loginLog):
err = s.loginLog(context.TODO(), mu.Action, mu.New)
case strings.HasPrefix(mu.Table, _pwdLog):
if mu.Action == "insert" {
err = s.changePWDRecord(context.TODO(), mu.New)
}
}
if err != nil {
log.Error("s.flush error(%v)", err)
time.Sleep(_retrySleep)
continue
}
break
}
log.Info("subproc key:%v,topic: %v, part:%v offset:%v,message %s,", res.Key, res.Topic, res.Partition, res.Offset, res.Value)
res.Commit()
}
}
// Close kafka consumer close.
func (s *Service) Close() (err error) {
return s.ds.Close()
}
// Ping check service health.
func (s *Service) Ping(c context.Context) (err error) {
return
}
func inetNtoA(sum uint32) string {
ip := make(net.IP, net.IPv4len)
ip[0] = byte((sum >> 24) & 0xFF)
ip[1] = byte((sum >> 16) & 0xFF)
ip[2] = byte((sum >> 8) & 0xFF)
ip[3] = byte(sum & 0xFF)
return ip.String()
}
func inetAtoN(s string) (sum uint32) {
ip := net.ParseIP(s)
if ip == nil {
return
}
ip = ip.To4()
if ip == nil {
return
}
sum += uint32(ip[0]) << 24
sum += uint32(ip[1]) << 16
sum += uint32(ip[2]) << 8
sum += uint32(ip[3])
return sum
}