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,22 @@
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/passport-game/cmd:all-srcs",
"//app/service/main/passport-game/conf:all-srcs",
"//app/service/main/passport-game/dao:all-srcs",
"//app/service/main/passport-game/http:all-srcs",
"//app/service/main/passport-game/model:all-srcs",
"//app/service/main/passport-game/service:all-srcs",
],
tags = ["automanaged"],
)

View File

@ -0,0 +1,67 @@
## passport-game-service
#### Version 1.13.1
> 1. 修复myinfo bug
#### Version 1.13.0
> 1. 增加用户手机邮箱信息
#### Version 1.12.0
> 1. 增加支持重置密码短信发送
#### Version 1.11.0
> 1. 缓存来自 origin 的结果
#### Version 1.10.1
> 1. 增加ut
#### Version 1.9.1
> 1. add x-forward header
#### Version 1.9.0
> 1. 增加regv3接口
#### Version 1.8.0
> 1. add other region db
> 2. update RemoteIP
#### Version 1.7.0
> 1. bm && mv dir
#### Version 1.6.2
> 1.renew token on origin in priority
#### Version 1.6.1
> 1.fix password not matches when salt is empty
#### Version 1.6.0
> 1.remove cold 30s when back to origin password error
> 2.add info log when back to origin ok
#### Version 1.5.0
> 1.use origin public and private key
#### Version 1.4.0
> 1.generate new public key and private key instead of using origin's
> 2.remove account table usage
> 3.change perm, info model to pb
> 4.add pb cache reading APIs
> 5.reduce cache reading times of api myinfo and oauth
> 6.add info API
#### Version 1.3.0
> 1.move to kratos
> 2.add oauth and renewToken dispatch
#### Version 1.2.1
> 1.token proc bugfix: unmarshall `ctime` `mtime` error
#### Version 1.2.0
> 1.token 消费优化
#### Version 1.1.0
> 1.api login
> 2.api get key
#### Version 1.0.0
> 1.基础api

View File

@ -0,0 +1,11 @@
# Owner
wanghuan01
zhoujiahui
# Author
wanghuan01
wutao
gezhangyuan
# Reviewer
wanghuan01

View File

@ -0,0 +1,17 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- gezhangyuan
- wanghuan01
- wutao
- zhoujiahui
labels:
- main
- service
- service/main/passport-game
options:
no_parent_owners: true
reviewers:
- gezhangyuan
- wanghuan01
- wutao

View File

@ -0,0 +1,38 @@
## passport-game-service
#### 项目简介
> 1.游戏云账号服务
#### 编译环境
> 请只用golang v1.8.x以上版本编译执行。
#### 依赖包
> 1.公共包go-common
#### 特别说明
> 1.model目录可能会被其他项目引用请谨慎更改并通知各方。
#### 部署注意
> 1.确定配置文件中 httpClient 节点中的 key 在 aso_apps 表中存在,且 issystem字段为 1。
> 2.确定使用上述 key 访问源站 /api/login 接口返回正常(非 -1、-403、-105
> 3.确定使用上述 key 访问源站 /api/login/oauth、/api/login/renewToken 接口返回正常(非 -1、-403
> 2.确定配置文件中 db.cloud 节点中所指向的数据库的 app 表包含了 identify-game-service 的 appkey。
#### 部署检查
```
ssh root@online-host
# expected -629
curl 'http://passport.bilibili.com/api/login?appkey=868fb9ea57619022&ts=1514374489&sign=12abbf6d77076cbb6627d4b8ecea1e43'
# expected -101
curl 'http://passport.bilibili.com/api/oauth?appkey=868fb9ea57619022&ts=1514374489&sign=12abbf6d77076cbb6627d4b8ecea1e43'
# expected -101
curl 'http://passport.bilibili.com/api/login/renewToken?appkey=868fb9ea57619022&ts=1514374489&sign=12abbf6d77076cbb6627d4b8ecea1e43'
# expected -101
curl 'http://api.bilibili.co/x/internal/identify-game/oauth?appkey=868fb9ea57619022&ts=1514374489&sign=12abbf6d77076cbb6627d4b8ecea1e43'
# expected -101
curl 'http://api.bilibili.co/x/internal/identify-game/renewtoken?appkey=868fb9ea57619022&ts=1514374489&sign=12abbf6d77076cbb6627d4b8ecea1e43'
```
#### 接入注意
> 1.使用本服务key 接口和 login 接口需要配套使用,如果用来加密密码的公钥与 key 接口返回的公钥不相同,会返回错误 -500。

View File

@ -0,0 +1,41 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_binary",
)
go_library(
name = "go_default_library",
srcs = ["main.go"],
data = ["passport-game-service.toml"],
importpath = "go-common/app/service/main/passport-game/cmd",
tags = ["automanaged"],
visibility = ["//visibility:private"],
deps = [
"//app/service/main/passport-game/conf:go_default_library",
"//app/service/main/passport-game/http:go_default_library",
"//app/service/main/passport-game/service:go_default_library",
"//library/log: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,48 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"time"
"go-common/app/service/main/passport-game/conf"
"go-common/app/service/main/passport-game/http"
"go-common/app/service/main/passport-game/service"
"go-common/library/log"
"go-common/library/net/trace"
)
func main() {
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Xlog)
defer log.Close()
trace.Init(conf.Conf.Tracer)
defer trace.Close()
// service init
srv := service.New(conf.Conf)
http.Init(conf.Conf, srv)
// signal handler
log.Info("passport-game-service start")
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("passport-game-service get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
srv.Close()
time.Sleep(time.Second * 2)
log.Info("passport-game-service exit")
return
case syscall.SIGHUP:
// TODO reload
default:
return
}
}
}

View File

@ -0,0 +1,87 @@
# This is a TOML document. Boom.
# 这个项目比较特殊,部署在云上的,需要保留一下配置
proxy = false
accountURI = "http://account.bilibili.co"
passportURI = "http://passport.bilibili.com"
family = "passport-game-service"
env = "qa"
[db.cloud]
addr = "172.16.33.205:3306"
dsn = "account:wx2U1MwXRyWEuURw@tcp(172.16.33.205:3306)/member_app1?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 2
queryTimeout = "1s"
execTimeout = "2s"
tranTimeout = "2s"
[db.cloud.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[db.otherRegion]
addr = "172.16.33.205:3306"
dsn = "account:wx2U1MwXRyWEuURw@tcp(172.16.33.205:3306)/member_app2?timeout=5s&readTimeout=5s&writeTimeout=5s&parseTime=true&loc=Local&charset=utf8,utf8mb4"
active = 5
idle = 2
queryTimeout = "1s"
execTimeout = "2s"
tranTimeout = "2s"
[db.otherRegion.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[memcache]
name = "passport-game-service"
proto = "tcp"
addr = "172.16.33.54:21211"
idle = 5
active = 10
dialTimeout = "1s"
readTimeout = "1s"
writeTimeout = "1s"
idleTimeout = "10s"
expire = "10h"
[httpClient]
key = "868fb9ea57619022"
secret = "test"
dial = "5s"
timeout = "10s"
keepAlive = "6s"
timer = 10
[httpClient.breaker]
window = "3s"
sleep = "100ms"
bucket = 10
ratio = 0.5
request = 100
[dispatcher]
name = "t1"
[dispatcher.oauth]
"origin"="http://api.bilibili.co/x/internal/identify-game/oauth"
"t1" = "http://api.bilibili.com/x/passport-game/oauth"
"t2" = "http://t2-api.bilibili.com/x/passport-game/oauth"
[dispatcher.renewToken]
"origin"="http://api.bilibili.co/x/internal/identify-game/renewtoken"
"t1" = "http://api.bilibili.com/x/passport-game/renewtoken"
"t2" = "http://t2-api.bilibili.com/x/passport-game/renewtoken"
[[dispatcher.regionInfos]]
region = "市北"
tokenSuffix = ""
[[dispatcher.regionInfos]]
region = "腾讯云1"
tokenSuffix = "t1"
[[dispatcher.regionInfos]]
region = "腾讯云2"
tokenSuffix = "t2"

View File

@ -0,0 +1,37 @@
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/passport-game/conf",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/passport-game/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/conf:go_default_library",
"//library/database/sql:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/trace: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,119 @@
package conf
import (
"errors"
"flag"
"go-common/app/service/main/passport-game/model"
"go-common/library/cache/memcache"
"go-common/library/conf"
"go-common/library/database/sql"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/trace"
"go-common/library/time"
"github.com/BurntSushi/toml"
)
var (
confPath string
// Conf conf.
Conf = &Config{}
client *conf.Client
)
// Config config.
type Config struct {
// Proxy if proxy
Proxy bool
// URIs
AccountURI string
PassportURI string
// Xlog log
Xlog *log.Config
// Tracer tracer
Tracer *trace.Config
// DB db
DB *DB
// Memcache memcache
Memcache *Memcache
// HTTPClient http client
HTTPClient *bm.ClientConfig
// HTTP server config
BM *bm.ServerConfig
// Dispatcher dispatcher
Dispatcher *Dispatcher
}
// Dispatcher dispatcher.
type Dispatcher struct {
Name string
Oauth map[string]string
RenewToken map[string]string
RegionInfos []*model.RegionInfo
}
// DB db config.
type DB struct {
Cloud *sql.Config
OtherRegion *sql.Config
}
// Memcache general memcache config.
type Memcache struct {
*memcache.Config
Expire time.Duration
}
func init() {
flag.StringVar(&confPath, "conf", "", "default config path")
}
// Init init config.
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,62 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"api.go",
"cache.go",
"dao.go",
"mc.go",
"mysql.go",
],
importpath = "go-common/app/service/main/passport-game/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/passport-game/conf:go_default_library",
"//app/service/main/passport-game/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/metadata:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"api_test.go",
"cache_test.go",
"dao_test.go",
"mc_test.go",
"mysql_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/passport-game/conf:go_default_library",
"//app/service/main/passport-game/model: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,396 @@
package dao
import (
"context"
"encoding/json"
"net/http"
"net/url"
"strconv"
"go-common/app/service/main/passport-game/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
)
// MyInfo get info from api.
func (d *Dao) MyInfo(c context.Context, accessKey string) (accountInfo *model.Info, err error) {
params := url.Values{}
params.Set("access_key", accessKey)
params.Set("type", "json")
var res struct {
Code int `json:"code"`
model.Info
}
if err = d.client.Get(c, d.myInfoURI, metadata.String(c, metadata.RemoteIP), params, &res); err != nil {
log.Error("myInfo url(%s) error(%v)", d.myInfoURI+"?"+params.Encode(), err)
return
}
if res.Code != 0 {
err = ecode.Int(res.Code)
log.Error("myInfo url(%s) error(%v)", d.myInfoURI+"?"+params.Encode(), err)
return
}
accountInfo = &res.Info
return
}
// Oauth oauth via passport api.
func (d *Dao) Oauth(c context.Context, uri, accessKey, from string) (token *model.Token, err error) {
params := url.Values{}
params.Set("access_key", accessKey)
params.Set("from", from)
var res struct {
Code int `json:"code"`
Token *struct {
Mid string `json:"mid"`
AppID int32 `json:"appid"`
AccessToken string `json:"access_key"`
CreateAt int64 `json:"create_at"`
UserID string `json:"userid"`
Uname string `json:"uname"`
Expires string `json:"expires"`
Permission string `json:"permission"`
} `json:"access_info,omitempty"`
Data *model.Token `json:"data,omitempty"`
}
if err = d.client.Get(c, uri, metadata.String(c, metadata.RemoteIP), params, &res); err != nil {
log.Error("model oauth url(%s) error(%v)", uri+"?"+params.Encode(), err)
return
}
if res.Code != 0 {
err = ecode.Int(res.Code)
log.Error("model oauth url(%s) error(%v)", uri+"?"+params.Encode(), err)
return
}
if res.Token != nil {
t := res.Token
var mid int64
if mid, err = strconv.ParseInt(t.Mid, 10, 64); err != nil {
log.Error("strconv.ParseInt(%s, 10, 64) error(%v)", t.Mid, err)
return
}
var expires int64
if expires, err = strconv.ParseInt(t.Expires, 10, 64); err != nil {
log.Error("strconv.ParseInt(%s, 10, 64) error(%v)", t.Expires, err)
return
}
token = &model.Token{
Mid: mid,
AppID: t.AppID,
AccessToken: t.AccessToken,
CreateAt: t.CreateAt,
UserID: t.UserID,
Uname: t.Uname,
Expires: expires,
Permission: t.Permission,
}
} else {
token = res.Data
}
return
}
// Login login via model api.
func (d *Dao) Login(c context.Context, query, cookie string) (loginToken *model.LoginToken, err error) {
req, err := http.NewRequest("GET", d.loginURI+"?"+query, nil)
if err != nil {
log.Error("http.NewRequest(GET, %s) error(%v)", d.loginURI+"?"+query, err)
return
}
req.Header.Set("Cookie", cookie)
req.Header.Set("X-BACKEND-BILI-REAL-IP", metadata.String(c, metadata.RemoteIP))
var res struct {
Code int `json:"code"`
Mid int64 `json:"mid"`
AccessKey string `json:"access_key"`
Expires int64 `json:"expires"`
}
if err = d.client.Do(c, req, &res); err != nil {
log.Error("model login url(%s) error(%v)", d.loginURI+"?"+query, err)
return
}
if res.Code != 0 {
err = ecode.Int(res.Code)
log.Error("model login url(%s) error(%v)", d.loginURI+"?"+query, err)
return
}
loginToken = &model.LoginToken{
Mid: res.Mid,
AccessKey: res.AccessKey,
Expires: res.Expires,
}
return
}
// LoginOrigin login via passport api.
func (d *Dao) LoginOrigin(c context.Context, userid, rsaPwd string) (loginToken *model.LoginToken, err error) {
params := url.Values{}
params.Set("userid", userid)
params.Set("pwd", rsaPwd)
var res struct {
Code int `json:"code"`
Mid int64 `json:"mid"`
AccessKey string `json:"access_key"`
Expires int64 `json:"expires"`
}
if err = d.client.Get(c, d.loginURI, metadata.String(c, metadata.RemoteIP), params, &res); err != nil {
log.Error("login url(%s) error(%v)", d.loginURI+"?"+params.Encode(), err)
return
}
if res.Code != 0 {
err = ecode.Int(res.Code)
log.Error("login url(%s) error(%v)", d.loginURI+"?"+params.Encode(), err)
return
}
str, _ := json.Marshal(res)
log.Info("login url(%s) res(%s)", d.loginURI+"?"+params.Encode(), str)
loginToken = &model.LoginToken{
Mid: res.Mid,
AccessKey: res.AccessKey,
Expires: res.Expires,
}
return
}
// RSAKeyOrigin get rsa pub key and ts hash via passport api.
func (d *Dao) RSAKeyOrigin(c context.Context) (key *model.RSAKey, err error) {
var res struct {
*model.RSAKey
Code int `json:"code"`
}
params := url.Values{}
if err = d.client.Get(c, d.getKeyURI, metadata.String(c, metadata.RemoteIP), params, &res); err != nil {
log.Error("key url(%s) error(%v)", d.getKeyURI+"?"+params.Encode(), err)
return
}
if res.Code != 0 {
err = ecode.Int(res.Code)
log.Error("key url(%s) error(%v)", d.getKeyURI+"?"+params.Encode(), err)
return
}
key = res.RSAKey
return
}
// RenewToken renew token via passport api.
func (d *Dao) RenewToken(c context.Context, uri, ak, from string) (renewToken *model.RenewToken, err error) {
params := url.Values{}
params.Set("access_key", ak)
params.Set("from", from)
var res struct {
Code int `json:"code"`
Expires int64 `json:"expires"`
Data struct {
Expires int64 `json:"expires"`
}
}
if err = d.client.Get(c, uri, metadata.String(c, metadata.RemoteIP), params, &res); err != nil {
log.Error("renewtoken url(%s) error(%v)", uri+"?"+params.Encode(), err)
return
}
if res.Code != 0 {
err = ecode.Int(res.Code)
log.Error("renewtoken url(%s) error(%v)", uri+"?"+params.Encode(), err)
return
}
expires := res.Expires
if expires == 0 {
expires = res.Data.Expires
}
renewToken = &model.RenewToken{
Expires: expires,
}
return
}
// RegV3 RegV3
func (d *Dao) RegV3(c context.Context, tdoRegV3 model.TdoRegV3) (regV3 *model.ResRegV3, err error) {
p := url.Values{}
p.Add("userpwd", tdoRegV3.Arg.Pwd)
p.Add("userid", tdoRegV3.Arg.User)
p.Add("captcha", tdoRegV3.Arg.Captcha)
p.Add("ctoken", tdoRegV3.Arg.Ctoken)
req, err := d.client.NewRequest(http.MethodPost, d.regV3URI, tdoRegV3.IP, p)
if err != nil {
log.Error("client.NewRequest(GET, %s) error(%v)", req.URL.String(), err)
return
}
req.Header.Set("X-Forwarded-For", tdoRegV3.IP)
req.Header.Set("Cookie", tdoRegV3.Cookie)
var response struct {
Code int `json:"code"`
Mid int `json:"mid"`
}
if err = d.client.Do(c, req, &response); err != nil {
log.Error("client.Do(%s) error(%v)", req.URL.String(), err)
return
}
if response.Code != ecode.OK.Code() {
log.Warn("regv3 url(%s) code(%d)", req.URL.String(), response.Code)
err = ecode.Int(response.Code)
return
}
regV3 = new(model.ResRegV3)
regV3.Mid = response.Mid
return
}
// RegV2 RegV2
func (d *Dao) RegV2(c context.Context, tdoRegV2 model.TdoRegV2) (regV2 *model.ResRegV2, err error) {
p := url.Values{}
p.Add("captcha", tdoRegV2.Arg.Captcha)
p.Add("ctoken", tdoRegV2.Arg.Ctoken)
req, err := d.client.NewRequest(http.MethodPost, d.regV2URI, tdoRegV2.IP, p)
if err != nil {
log.Error("client.NewRequest(GET, %s) error(%v)", req.URL.String(), err)
return
}
req.Header.Set("X-Forwarded-For", tdoRegV2.IP)
req.Header.Set("Cookie", tdoRegV2.Cookie)
var response struct {
Code int `json:"code"`
Mid int `json:"mid"`
AccessKey string `json:"access_key"`
}
if err = d.client.Do(c, req, &response); err != nil {
log.Error("client.Do(%s) error(%v)", req.URL.String(), err)
return
}
if response.Code != ecode.OK.Code() {
log.Warn("reg v2 url(%s) code(%d)", req.URL.String(), response.Code)
err = ecode.Int(response.Code)
return
}
regV2 = new(model.ResRegV2)
regV2.Mid = response.Mid
regV2.AccessKey = response.AccessKey
return
}
// Reg Reg
func (d *Dao) Reg(c context.Context, tdoReg model.TdoReg) (reg *model.ResReg, err error) {
p := url.Values{}
p.Add("userpwd", tdoReg.Arg.Userpwd)
p.Add("user", tdoReg.Arg.User)
p.Add("email", tdoReg.Arg.Email)
// new request
req, err := d.client.NewRequest(http.MethodPost, d.regURI, tdoReg.IP, p)
if err != nil {
log.Error("client.NewRequest(GET, %s) error(%v)", req.URL.String(), err)
return
}
req.Header.Set("X-Forwarded-For", tdoReg.IP)
req.Header.Set("Cookie", tdoReg.Cookie)
var response struct {
Code int `json:"code"`
Mid int `json:"mid"`
}
if err = d.client.Do(c, req, &response); err != nil {
log.Error("client.Do(%s) error(%v)", req.URL.String(), err)
return
}
if response.Code != ecode.OK.Code() {
log.Warn("reg url(%s) code(%d)", req.URL.String(), response.Code)
err = ecode.Int(response.Code)
return
}
reg = new(model.ResReg)
reg.Mid = response.Mid
return
}
// ByTel ByTel
func (d *Dao) ByTel(c context.Context, tdoByTel model.TdoByTel) (byTel *model.ResByTel, err error) {
p := url.Values{}
p.Add("userpwd", tdoByTel.Arg.Userpwd)
p.Add("tel", tdoByTel.Arg.Tel)
p.Add("captcha", tdoByTel.Arg.Captcha)
p.Add("country_id", tdoByTel.Arg.CountryID)
p.Add("uname", tdoByTel.Arg.Uname)
// new request
req, err := d.client.NewRequest(http.MethodPost, d.byTelURI, tdoByTel.IP, p)
if err != nil {
log.Error("client.NewRequest(GET, %s) error(%v)", req.URL.String(), err)
return
}
req.Header.Set("X-Forwarded-For", tdoByTel.IP)
req.Header.Set("Cookie", tdoByTel.Cookie)
var response struct {
Code int `json:"code"`
Data struct {
Mid int `json:"mid"`
AccessKey string `json:"access_key"`
}
}
if err = d.client.Do(c, req, &response); err != nil {
log.Error("client.Do(%s) error(%v)", req.URL.String(), err)
return
}
if response.Code != ecode.OK.Code() {
log.Warn("byTel url(%s) code(%d)", req.URL.String(), response.Code)
err = ecode.Int(response.Code)
return
}
byTel = new(model.ResByTel)
byTel.Mid = response.Data.Mid
byTel.AccessKey = response.Data.AccessKey
return
}
// Captcha Captcha
func (d *Dao) Captcha(c context.Context, ip string) (captchaData *model.CaptchaData, err error) {
p := url.Values{}
req, err := d.client.NewRequest(http.MethodGet, d.captchaURI, ip, p)
if err != nil {
log.Error("client.NewRequest(GET, %s) error(%v)", req.URL.String(), err)
return
}
resCaptcha := new(model.ResCaptcha)
req.Header.Set("X-Forwarded-For", ip)
if err = d.client.Do(c, req, &resCaptcha); err != nil {
log.Error("client.Do(%s) error(%v)", req.URL.String(), err)
return
}
err = ecode.Int(resCaptcha.Code)
captchaData = &resCaptcha.Data
return
}
// SendSms SendSms
func (d *Dao) SendSms(c context.Context, tdoSendSms model.TdoSendSms) (err error) {
p := url.Values{}
p.Add("captcha", tdoSendSms.Arg.Captcha)
p.Add("tel", tdoSendSms.Arg.Tel)
p.Add("country_id", tdoSendSms.Arg.CountryID)
p.Add("ctoken", tdoSendSms.Arg.Ctoken)
p.Add("reset_pwd", strconv.FormatBool(tdoSendSms.Arg.ResetPwd))
req, err := d.client.NewRequest(http.MethodGet, d.sendSmsURI, tdoSendSms.IP, p)
if err != nil {
log.Error("client.NewRequest(GET, %s) error(%v)", req.URL.String(), err)
return
}
req.Header.Set("X-Forwarded-For", tdoSendSms.IP)
req.Header.Set("Cookie", tdoSendSms.Cookie)
resCaptcha := new(model.ResCaptcha)
if err = d.client.Do(c, req, &resCaptcha); err != nil {
log.Error("client.Do(%s) error(%v)", req.URL.String(), err)
return
}
err = ecode.Int(resCaptcha.Code)
return
}

View File

@ -0,0 +1,97 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoMyInfo(t *testing.T) {
var (
c = context.TODO()
accessKey = "123456"
)
convey.Convey("MyInfo", t, func(ctx convey.C) {
accountInfo, err := d.MyInfo(c, accessKey)
ctx.Convey("Then err should be nil.accountInfo should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(accountInfo, convey.ShouldBeNil)
})
})
}
func TestDaoOauth(t *testing.T) {
var (
c = context.TODO()
uri = "https://wwww.baidu.com"
accessKey = "123456"
from = "baidu"
)
convey.Convey("Oauth", t, func(ctx convey.C) {
token, err := d.Oauth(c, uri, accessKey, from)
ctx.Convey("Then err should be nil.token should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(token, convey.ShouldBeNil)
})
})
}
func TestDaoLogin(t *testing.T) {
var (
c = context.TODO()
query = "123"
cookie = "123"
)
convey.Convey("Login", t, func(ctx convey.C) {
loginToken, err := d.Login(c, query, cookie)
ctx.Convey("Then err should be nil.loginToken should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(loginToken, convey.ShouldBeNil)
})
})
}
func TestDaoLoginOrigin(t *testing.T) {
var (
c = context.TODO()
userid = "1"
rsaPwd = "123456"
)
convey.Convey("LoginOrigin", t, func(ctx convey.C) {
loginToken, err := d.LoginOrigin(c, userid, rsaPwd)
ctx.Convey("Then err should be nil.loginToken should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(loginToken, convey.ShouldBeNil)
})
})
}
func TestDaoRSAKeyOrigin(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("RSAKeyOrigin", t, func(ctx convey.C) {
key, err := d.RSAKeyOrigin(c)
ctx.Convey("Then err should be nil.key should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(key, convey.ShouldNotBeNil)
})
})
}
func TestDaoRenewToken(t *testing.T) {
var (
c = context.TODO()
uri = "https://wwww.baidu.com"
ak = "234"
from = "234"
)
convey.Convey("RenewToken", t, func(ctx convey.C) {
renewToken, err := d.RenewToken(c, uri, ak, from)
ctx.Convey("Then err should be nil.renewToken should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(renewToken, convey.ShouldBeNil)
})
})
}

View File

@ -0,0 +1,36 @@
package dao
import (
"context"
"fmt"
"strconv"
"strings"
"go-common/app/service/main/passport-game/model"
"go-common/library/log"
)
// TokenPBCache get token pb cache.
func (d *Dao) TokenPBCache(c context.Context, key string) (res *model.Perm, err error) {
if !strings.HasPrefix(key, _keyPrefixTokenPB) {
err = fmt.Errorf("invalid cache key %s, key pattern is %s{token}", key, _keyPrefixInfoPB)
return
}
token := key[len(_keyPrefixTokenPB):]
return d.TokenCache(c, token)
}
// InfoPBCache get info pb cache.
func (d *Dao) InfoPBCache(c context.Context, key string) (res *model.Info, err error) {
if !strings.HasPrefix(key, _keyPrefixInfoPB) {
err = fmt.Errorf("invalid cache key %s, key pattern is %s{mid}", key, _keyPrefixInfoPB)
return
}
midStr := key[len(_keyPrefixInfoPB):]
mid, err := strconv.ParseInt(midStr, 10, 64)
if err != nil {
log.Error("strconv.ParseInt(%s, 10, 64) error(%v)", midStr, err)
return
}
return d.InfoCache(c, mid)
}

View File

@ -0,0 +1,36 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaoTokenPBCache(t *testing.T) {
var (
c = context.TODO()
key = "123456"
)
convey.Convey("TokenPBCache", t, func(ctx convey.C) {
res, err := d.TokenPBCache(c, key)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(res, convey.ShouldBeNil)
})
})
}
func TestDaoInfoPBCache(t *testing.T) {
var (
c = context.TODO()
key = "123456"
)
convey.Convey("InfoPBCache", t, func(ctx convey.C) {
res, err := d.InfoPBCache(c, key)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(res, convey.ShouldBeNil)
})
})
}

View File

@ -0,0 +1,96 @@
package dao
import (
"context"
"fmt"
"time"
"go-common/app/service/main/passport-game/conf"
"go-common/library/cache/memcache"
"go-common/library/database/sql"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
// Dao dao
type Dao struct {
c *conf.Config
getMemberStmt []*sql.Stmt
cloudDB *sql.DB
otherRegion *sql.DB
mc *memcache.Pool
mcExpire int32
client *bm.Client
myInfoURI string
loginURI string
getKeyURI string
regV3URI string
regV2URI string
regURI string
byTelURI string
captchaURI string
sendSmsURI string
}
const (
_myInfoURI = "/api/myinfo"
_loginURI = "/api/login"
_getKeyURI = "/api/login/get_key"
_regV3URI = "/api/reg/regV3"
_regV2URI = "/api/reg/regV2"
_regURI = "/api/reg/reg"
_byTelURI = "/api/reg/byTelGame"
_captchaURI = "/bilicaptcha/token"
_sendSmsURI = "/api/sms/sendCaptcha"
)
// New dao
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
cloudDB: sql.NewMySQL(c.DB.Cloud),
otherRegion: sql.NewMySQL(c.DB.OtherRegion),
mc: memcache.NewPool(c.Memcache.Config),
mcExpire: int32(time.Duration(c.Memcache.Expire) / time.Second),
client: bm.NewClient(c.HTTPClient),
myInfoURI: c.AccountURI + _myInfoURI,
loginURI: c.PassportURI + _loginURI,
getKeyURI: c.PassportURI + _getKeyURI,
regV3URI: c.PassportURI + _regV3URI,
regV2URI: c.PassportURI + _regV2URI,
regURI: c.PassportURI + _regURI,
byTelURI: c.PassportURI + _byTelURI,
captchaURI: c.PassportURI + _captchaURI,
sendSmsURI: c.PassportURI + _sendSmsURI,
}
d.getMemberStmt = make([]*sql.Stmt, _memberShard)
for i := 0; i < _memberShard; i++ {
d.getMemberStmt[i] = d.cloudDB.Prepared(fmt.Sprintf(_getMemberInfoSQL, i))
}
return
}
// Ping verify server is ok.
func (d *Dao) Ping(c context.Context) (err error) {
if err = d.cloudDB.Ping(c); err != nil {
log.Info("dao.cloudDB.Ping() error(%v)", err)
}
if err = d.otherRegion.Ping(c); err != nil {
log.Info("dao.otherRegion.Ping() error(%v)", err)
}
return d.pingMC(c)
}
// Close close connections of mc, cloudDB.
func (d *Dao) Close() (err error) {
if d.cloudDB != nil {
d.cloudDB.Close()
}
if d.otherRegion != nil {
d.otherRegion.Close()
}
if d.mc != nil {
d.mc.Close()
}
return
}

View File

@ -0,0 +1,34 @@
package dao
import (
"flag"
"os"
"testing"
"go-common/app/service/main/passport-game/conf"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "dev" {
flag.Set("app_id", "main.account.passport-game-service")
flag.Set("conf_token", "6461f64e47f084a2c9bbd505182dbe39")
flag.Set("tree_id", "3791")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}

View File

@ -0,0 +1,243 @@
package dao
import (
"context"
"math/rand"
"strconv"
"go-common/app/service/main/passport-game/model"
"go-common/library/cache/memcache"
"go-common/library/log"
)
const (
_keyPrefixInfoPB = "pa2_"
_keyPrefixTokenPB = "pt_"
_keyPrefixOriginMissMatchFlag = "m_"
_keyPrefixOriginToken = "pot_"
_missMatchFlagExpireSeconds = 30 // 30 seconds
)
func keyInfoPB(mid int64) string {
return _keyPrefixInfoPB + strconv.FormatInt(mid, 10)
}
func keyTokenPB(accessToken string) string {
return _keyPrefixTokenPB + accessToken
}
func keyOriginToken(accessToken string) string {
return _keyPrefixOriginToken + accessToken
}
func keyOriginMissMatchFlag(identify string) string {
return _keyPrefixOriginMissMatchFlag + identify
}
// pingMC check connection success.
func (d *Dao) pingMC(c context.Context) (err error) {
item := &memcache.Item{
Key: "ping",
Value: []byte{1},
Expiration: d.mcExpire,
}
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Set(item); err != nil {
log.Error("conn.Set(%v) error(%v)", item, err)
}
return
}
// SetInfoCache set info into cache.
func (d *Dao) SetInfoCache(c context.Context, info *model.Info) (err error) {
item := &memcache.Item{
Key: keyInfoPB(info.Mid),
Object: info,
Flags: memcache.FlagProtobuf,
Expiration: d.mcExpire,
}
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Set(item); err != nil {
log.Error("conn.Set(%s) error(%v)", item.Key, err)
}
return
}
// InfoCache get info cache from cache.
func (d *Dao) InfoCache(c context.Context, mid int64) (info *model.Info, err error) {
key := keyInfoPB(mid)
conn := d.mc.Get(c)
defer conn.Close()
var item *memcache.Item
if item, err = conn.Get(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
log.Error("conn.Get(%s) error(%v)", key, err)
return
}
info = new(model.Info)
if err = conn.Scan(item, info); err != nil {
log.Error("conn.Scan(%s, %s) error(%v)", key, item.Value, err)
}
return
}
// SetTokenCache set token into cache.
func (d *Dao) SetTokenCache(c context.Context, token *model.Perm) (err error) {
item := &memcache.Item{
Key: keyTokenPB(token.AccessToken),
Object: token,
Flags: memcache.FlagProtobuf,
Expiration: d.mcExpire,
}
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Set(item); err != nil {
log.Error("conn.Set(%s) error(%v)", item.Key, err)
}
return
}
// TokenCache get token from cache.
func (d *Dao) TokenCache(c context.Context, accessToken string) (token *model.Perm, err error) {
key := keyTokenPB(accessToken)
conn := d.mc.Get(c)
defer conn.Close()
item, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
log.Error("conn.Get(%s) error(%v)", key, err)
return
}
token = new(model.Perm)
if err = conn.Scan(item, token); err != nil {
log.Error("conn.Scan(%s, %s) error(%v)", item.Key, item.Value, err)
}
return
}
// DelTokenCache delete token from cache.
func (d *Dao) DelTokenCache(c context.Context, accessToken string) (err error) {
key := keyTokenPB(accessToken)
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
log.Error("conn.Delete(%s) error(%v)", key, err)
}
return
}
// SetOriginMissMatchFlagCache set origin miss match flag cache.
func (d *Dao) SetOriginMissMatchFlagCache(c context.Context, identify string, flag []byte) (err error) {
item := &memcache.Item{
Key: keyOriginMissMatchFlag(identify),
Value: flag,
Expiration: _missMatchFlagExpireSeconds,
}
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Set(item); err != nil {
log.Error("conn.Set(%s) error(%v)", item.Key, err)
}
return
}
// OriginMissMatchFlagCache get origin miss match flag.
func (d *Dao) OriginMissMatchFlagCache(c context.Context, identify string) (res []byte, err error) {
key := keyOriginMissMatchFlag(identify)
conn := d.mc.Get(c)
defer conn.Close()
var item *memcache.Item
if item, err = conn.Get(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
log.Error("conn.Get(%s) error(%v)", key, err)
return
}
res = item.Value
return
}
// DelOriginMissMatchFlagCache delete origin miss match flag.
func (d *Dao) DelOriginMissMatchFlagCache(c context.Context, identify string) (err error) {
key := keyOriginMissMatchFlag(identify)
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
log.Error("conn.Delete(%s) error(%v)", key, err)
}
return
}
// SetOriginTokenCache set passport token into cache.
func (d *Dao) SetOriginTokenCache(c context.Context, token *model.Token) (err error) {
item := &memcache.Item{
Key: keyOriginToken(token.AccessToken),
Object: token,
Flags: memcache.FlagJSON,
Expiration: 60 + rand.Int31n(600),
}
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Set(item); err != nil {
log.Error("conn.Set(%s) error(%v)", item.Key, err)
return
}
return
}
// OriginTokenCache set passport token into cache.
func (d *Dao) OriginTokenCache(c context.Context, accessToken string) (token *model.Token, err error) {
key := keyOriginToken(accessToken)
conn := d.mc.Get(c)
defer conn.Close()
item, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
log.Error("conn.Get(%s) error(%v)", key, err)
return
}
token = new(model.Token)
if err = conn.Scan(item, token); err != nil {
log.Error("conn.Scan(%s, %s) error(%v)", item.Key, item.Value, err)
return
}
return
}
// DelOriginTokenCache delete passport token from cache.
func (d *Dao) DelOriginTokenCache(c context.Context, accessToken string) (err error) {
key := keyOriginToken(accessToken)
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
log.Error("conn.Delete(%s) error(%v)", key, err)
return
}
return
}

View File

@ -0,0 +1,193 @@
package dao
import (
"context"
"go-common/app/service/main/passport-game/model"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaokeyInfoPB(t *testing.T) {
var (
mid = int64(12)
)
convey.Convey("keyInfoPB", t, func(ctx convey.C) {
p1 := keyInfoPB(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaokeyTokenPB(t *testing.T) {
var (
accessToken = "123"
)
convey.Convey("keyTokenPB", t, func(ctx convey.C) {
p1 := keyTokenPB(accessToken)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaokeyOriginMissMatchFlag(t *testing.T) {
var (
identify = "123"
)
convey.Convey("keyOriginMissMatchFlag", t, func(ctx convey.C) {
p1 := keyOriginMissMatchFlag(identify)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaopingMC(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("pingMC", t, func(ctx convey.C) {
err := d.pingMC(c)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoSetInfoCache(t *testing.T) {
var (
c = context.TODO()
info = &model.Info{}
)
convey.Convey("SetInfoCache", t, func(ctx convey.C) {
err := d.SetInfoCache(c, info)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoInfoCache(t *testing.T) {
var (
c = context.TODO()
mid = int64(0)
)
convey.Convey("InfoCache", t, func(ctx convey.C) {
info, err := d.InfoCache(c, mid)
ctx.Convey("Then err should be nil.info should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(info, convey.ShouldNotBeNil)
})
})
}
func TestDaoTokenCache(t *testing.T) {
var (
c = context.TODO()
accessToken = "123456"
token = &model.Perm{
Mid: -1,
AccessToken: accessToken,
}
)
convey.Convey("TestDaoTokenCache", t, func(ctx convey.C) {
err := d.SetTokenCache(c, token)
ctx.Convey("SetTokenCache", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
token, err := d.TokenCache(c, accessToken)
ctx.Convey("TokenCache", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(token, convey.ShouldNotBeNil)
})
err = d.DelTokenCache(c, accessToken)
ctx.Convey("DelTokenCache", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
token, err = d.TokenCache(c, accessToken)
ctx.Convey("DeletedTokenCache", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(token, convey.ShouldBeNil)
})
})
}
func TestDaoSetOriginMissMatchFlagCache(t *testing.T) {
var (
c = context.TODO()
identify = "123456"
flag = []byte("")
)
convey.Convey("SetOriginMissMatchFlagCache", t, func(ctx convey.C) {
err := d.SetOriginMissMatchFlagCache(c, identify, flag)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoOriginMissMatchFlagCache(t *testing.T) {
var (
c = context.TODO()
identify = "123456"
)
convey.Convey("OriginMissMatchFlagCache", t, func(ctx convey.C) {
res, err := d.OriginMissMatchFlagCache(c, identify)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
}
func TestDaoDelOriginMissMatchFlagCache(t *testing.T) {
var (
c = context.TODO()
identify = "123456"
)
convey.Convey("DelOriginMissMatchFlagCache", t, func(ctx convey.C) {
err := d.DelOriginMissMatchFlagCache(c, identify)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoOriginTokenCache(t *testing.T) {
var (
c = context.TODO()
accessToken = "123456"
token = &model.Token{
Mid: -1,
AccessToken: accessToken,
}
)
convey.Convey("TestDaoOriginTokenCache", t, func(ctx convey.C) {
err := d.SetOriginTokenCache(c, token)
ctx.Convey("SetOriginTokenCache", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
token, err := d.OriginTokenCache(c, accessToken)
ctx.Convey("OriginTokenCache", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(token, convey.ShouldNotBeNil)
})
err = d.DelOriginTokenCache(c, accessToken)
ctx.Convey("DelOriginTokenCache", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
token, err = d.OriginTokenCache(c, accessToken)
ctx.Convey("DeletedOriginTokenCache", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(token, convey.ShouldBeNil)
})
})
}

View File

@ -0,0 +1,147 @@
package dao
import (
"context"
"database/sql"
"go-common/app/service/main/passport-game/model"
xsql "go-common/library/database/sql"
"go-common/library/log"
)
const (
_memberShard = 30
_getMemberInfoSQL = "SELECT mid,face FROM member_%02d WHERE mid=?"
_getAppsSQL = "SELECT appid,appkey,app_secret FROM app"
_addTokenSQL = "INSERT INTO app_perm (mid,appid,app_subid,access_token,create_at,expires) VALUES (?,?,?,?,?,?)"
_updateTokenSQL = "UPDATE app_perm SET expires=? WHERE access_token=? AND expires<?"
_getTokenSQL = "SELECT mid,appid,app_subid,access_token,create_at,expires FROM app_perm WHERE access_token=?"
_getAsoAccountSQL = "SELECT mid,userid,uname,pwd,salt,isleak FROM aso_account WHERE userid=? OR email=? OR tel=?"
_getAccountInfoSQL = "SELECT mid,userid,uname,email,tel FROM aso_account WHERE mid=?"
)
func hit(mid int64) int64 {
return mid % _memberShard
}
// MemberInfo get member info.
func (d *Dao) MemberInfo(c context.Context, mid int64) (res *model.Info, err error) {
var row = d.getMemberStmt[hit(mid)].QueryRow(c, mid)
res = new(model.Info)
if err = row.Scan(&res.Mid, &res.Face); err != nil {
if err == xsql.ErrNoRows {
res = nil
err = nil
} else {
log.Error("row.Scan() error(%v)", err)
}
}
return
}
// Apps get all apps.
func (d *Dao) Apps(c context.Context) (res []*model.App, err error) {
var rows *xsql.Rows
if rows, err = d.cloudDB.Query(c, _getAppsSQL); err != nil {
log.Error("get apps, dao.cloudDB.Query(%s) error(%v)", _getAppsSQL, err)
return
}
defer rows.Close()
for rows.Next() {
app := new(model.App)
if err = rows.Scan(&app.AppID, &app.AppKey, &app.AppSecret); err != nil {
log.Error("row.Scan() error(%v)", err)
res = nil
return
}
res = append(res, app)
}
err = rows.Err()
return
}
// AddToken add token.
func (d *Dao) AddToken(c context.Context, t *model.Perm) (affected int64, err error) {
var res sql.Result
if res, err = d.cloudDB.Exec(c, _addTokenSQL, t.Mid, t.AppID, t.AppSubID, t.AccessToken, t.CreateAt, t.Expires); err != nil {
log.Error("add token, dao.cloudDB.Exec(%d, %d, %d, %s, %d, %d) error(%v)", t.Mid, t.AppID, t.AppSubID, t.AccessToken, t.CreateAt, t.Expires, err)
return
}
return res.RowsAffected()
}
// UpdateToken update token.
func (d *Dao) UpdateToken(c context.Context, t *model.Perm) (affected int64, err error) {
var res sql.Result
if res, err = d.cloudDB.Exec(c, _updateTokenSQL, t.Expires, t.AccessToken, t.Expires); err != nil {
log.Error("update token, dao.cloudDB.Exec(%d, %s, %d) error(%v)", t.Expires, t.AccessToken, t.Expires, err)
return
}
return res.RowsAffected()
}
// Token get token.
func (d *Dao) Token(c context.Context, accessToken string) (res *model.Perm, err error) {
row := d.cloudDB.QueryRow(c, _getTokenSQL, accessToken)
res = new(model.Perm)
if err = row.Scan(&res.Mid, &res.AppID, &res.AppSubID, &res.AccessToken, &res.CreateAt, &res.Expires); err != nil {
if err == xsql.ErrNoRows {
res = nil
err = nil
} else {
log.Error("row.Scan() error(%v)", err)
}
}
return
}
// AsoAccount get aso account.
func (d *Dao) AsoAccount(c context.Context, identify, identifyHash string) (res []*model.AsoAccount, err error) {
var rows *xsql.Rows
if rows, err = d.cloudDB.Query(c, _getAsoAccountSQL, identify, identifyHash, identifyHash); err != nil {
log.Error("get apps, dao.cloudDB.Query(%s) error(%v)", _getAsoAccountSQL, err)
return
}
for rows.Next() {
aso := new(model.AsoAccount)
if err = rows.Scan(&aso.Mid, &aso.UserID, &aso.Uname, &aso.Pwd, &aso.Salt, &aso.Isleak); err != nil {
log.Error("row.Scan() error(%v)", err)
res = nil
return
}
res = append(res, aso)
}
err = rows.Err()
return
}
// AccountInfo get account info.
func (d *Dao) AccountInfo(c context.Context, mid int64) (res *model.AsoAccount, err error) {
row := d.cloudDB.QueryRow(c, _getAccountInfoSQL, mid)
res = new(model.AsoAccount)
if err = row.Scan(&res.Mid, &res.UserID, &res.Uname, &res.Email, &res.Tel); err != nil {
if err == xsql.ErrNoRows {
res = nil
err = nil
} else {
log.Error("row.Scan() error(%v)", err)
}
}
return
}
// TokenFromOtherRegion get token from otherRegion.
func (d *Dao) TokenFromOtherRegion(c context.Context, accessToken string) (res *model.Perm, err error) {
row := d.otherRegion.QueryRow(c, _getTokenSQL, accessToken)
res = new(model.Perm)
if err = row.Scan(&res.Mid, &res.AppID, &res.AppSubID, &res.AccessToken, &res.CreateAt, &res.Expires); err != nil {
if err == xsql.ErrNoRows {
res = nil
err = nil
return
}
log.Error("row.Scan() error(%v)", err)
return
}
return
}

View File

@ -0,0 +1,133 @@
package dao
import (
"context"
"go-common/app/service/main/passport-game/model"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestDaohit(t *testing.T) {
var (
mid = int64(1)
)
convey.Convey("hit", t, func(ctx convey.C) {
p1 := hit(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
}
func TestDaoMemberInfo(t *testing.T) {
var (
c = context.TODO()
mid = int64(1)
)
convey.Convey("MemberInfo", t, func(ctx convey.C) {
res, err := d.MemberInfo(c, mid)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldBeNil)
})
})
}
func TestDaoApps(t *testing.T) {
var (
c = context.TODO()
)
convey.Convey("Apps", t, func(ctx convey.C) {
res, err := d.Apps(c)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
}
func TestDaoAddToken(t *testing.T) {
var (
c = context.TODO()
no = &model.Perm{}
)
convey.Convey("AddToken", t, func(ctx convey.C) {
affected, err := d.AddToken(c, no)
ctx.Convey("Then err should be nil.affected should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(affected, convey.ShouldNotBeNil)
})
})
}
func TestDaoUpdateToken(t *testing.T) {
var (
c = context.TODO()
no = &model.Perm{}
)
convey.Convey("UpdateToken", t, func(ctx convey.C) {
affected, err := d.UpdateToken(c, no)
ctx.Convey("Then err should be nil.affected should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(affected, convey.ShouldNotBeNil)
})
})
}
func TestDaoToken(t *testing.T) {
var (
c = context.TODO()
accessToken = "123456"
)
convey.Convey("Token", t, func(ctx convey.C) {
res, err := d.Token(c, accessToken)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldBeNil)
})
})
}
func TestDaoAsoAccount(t *testing.T) {
var (
c = context.TODO()
identify = "123456"
identifyHash = "654321"
)
convey.Convey("AsoAccount", t, func(ctx convey.C) {
res, err := d.AsoAccount(c, identify, identifyHash)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldBeNil)
})
})
}
func TestDaoAccountInfo(t *testing.T) {
var (
c = context.TODO()
mid = int64(1)
)
convey.Convey("AccountInfo", t, func(ctx convey.C) {
res, err := d.AccountInfo(c, mid)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
}
func TestDaoTokenFromOtherRegion(t *testing.T) {
var (
c = context.TODO()
accessToken = "123456"
)
convey.Convey("TokenFromOtherRegion", t, func(ctx convey.C) {
res, err := d.TokenFromOtherRegion(c, accessToken)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldBeNil)
})
})
}

View File

@ -0,0 +1,44 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
)
go_library(
name = "go_default_library",
srcs = [
"account.go",
"cache.go",
"cloud.go",
"http.go",
"passport.go",
"passport_login.go",
"passport_reg.go",
"sign.go",
],
importpath = "go-common/app/service/main/passport-game/http",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/passport-game/conf:go_default_library",
"//app/service/main/passport-game/model:go_default_library",
"//app/service/main/passport-game/service:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/metadata: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,51 @@
package http
import (
"strconv"
"go-common/app/service/main/passport-game/model"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
func myInfo(c *bm.Context) {
var (
err error
params = c.Request.Form
accessKey = params.Get("access_key")
)
if accessKey == "" {
c.JSON(nil, ecode.RequestErr)
return
}
app, ok := c.Get("app")
if !ok {
c.JSON(nil, ecode.AppKeyInvalid)
return
}
info, err := srv.MyInfo(c, app.(*model.App), accessKey)
if err != nil {
log.Error("service.MyInfo(%s) error(%v)", accessKey, err)
c.JSON(nil, err)
return
}
c.JSON(info, nil)
}
func info(c *bm.Context) {
var (
err error
midStr = c.Request.Form.Get("mid")
)
if midStr == "" {
c.JSON(nil, ecode.RequestErr)
return
}
mid, err := strconv.ParseInt(midStr, 10, 64)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
c.JSON(srv.Info(c, mid), nil)
}

View File

@ -0,0 +1,49 @@
package http
import (
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
func infoPBCache(c *bm.Context) {
var (
err error
key = c.Request.Form.Get("key")
)
if key == "" {
c.JSON(nil, ecode.RequestErr)
return
}
info, err := srv.InfoPBCache(c, key)
if err != nil {
log.Error("service.InfoPBCache(%s) error(%v)", key, err)
res := map[string]interface{}{}
res["code"] = err
res["message"] = err.Error()
c.JSONMap(res, nil)
return
}
c.JSON(info, nil)
}
func tokenPBCache(c *bm.Context) {
var (
err error
key = c.Request.Form.Get("key")
)
if key == "" {
c.JSON(nil, ecode.RequestErr)
return
}
info, err := srv.TokenPBCache(c, key)
if err != nil {
log.Error("service.TokenPBCache(%s) error(%v)", key, err)
res := map[string]interface{}{}
res["code"] = err
res["message"] = err.Error()
c.JSONMap(res, nil)
return
}
c.JSON(info, nil)
}

View File

@ -0,0 +1,9 @@
package http
import (
"go-common/library/net/http/blademaster"
)
func regions(c *blademaster.Context) {
c.JSON(srv.Regions(c), nil)
}

View File

@ -0,0 +1,81 @@
package http
import (
"net/http"
"go-common/app/service/main/passport-game/conf"
"go-common/app/service/main/passport-game/service"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
var (
srv *service.Service
)
// Init init http sever instance.
func Init(c *conf.Config, s *service.Service) {
srv = s
// init inner router
engine := bm.DefaultServer(c.BM)
initRouter(engine)
// init inner server
if err := engine.Start(); err != nil {
log.Error("engine.Start error(%v)", err)
panic(err)
}
}
// initRouter init inner router.
func initRouter(e *bm.Engine) {
// health check
e.Ping(ping)
e.Register(register)
// new defined api lists
g := e.Group("/x/passport-game")
{
g.GET("/oauth", verify, oauth)
g.GET("/myinfo", verify, myInfo)
g.GET("/info", verify, info)
g.GET("/key", verify, getKeyProxy)
g.GET("/login", verify, loginProxy)
g.GET("/renewtoken", verify, renewToken)
g.GET("/regions", verify, regions)
g.POST("/reg/v3", verify, regV3)
g.POST("/reg/v2", verify, regV2)
g.POST("/reg", verify, reg)
g.POST("/reg/byTel", verify, byTel)
g.GET("/captcha", verify, captcha)
g.POST("/sendSms", verify, sendSms)
}
inner := e.Group("/cache/pb")
{
inner.GET("/token", tokenPBCache)
inner.GET("/info", infoPBCache)
}
}
func verify(c *bm.Context) {
app, err := verifySign(c, srv)
if err != nil {
c.JSON(nil, err)
c.Abort()
}
c.Set("app", app)
}
// ping check server ok.
func ping(c *bm.Context) {
if err := srv.Ping(c); err != nil {
log.Error("ping error(%v)", err)
c.AbortWithStatus(http.StatusServiceUnavailable)
}
}
// register support discovery.
func register(c *bm.Context) {
c.JSON(map[string]struct{}{}, nil)
}

View File

@ -0,0 +1,81 @@
package http
import (
"go-common/app/service/main/passport-game/model"
"go-common/app/service/main/passport-game/service"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
func oauth(c *bm.Context) {
var (
err error
params = c.Request.Form
accessKey = params.Get("access_key")
from = params.Get("from")
)
if accessKey == "" {
c.JSON(nil, ecode.RequestErr)
return
}
app, ok := c.Get("app")
if !ok {
c.JSON(nil, ecode.AppKeyInvalid)
return
}
var token *model.Token
if token, err = srv.Oauth(c, app.(*model.App), accessKey, from); err != nil {
log.Error("service.Oauth(%s) error(%v)", accessKey, err)
res := map[string]interface{}{}
if err == service.ErrDispatcherError {
res["message"] = err.Error()
}
c.JSONMap(res, err)
return
}
c.JSON(token, nil)
}
func getKeyOrigin(c *bm.Context) {
var err error
var t *model.RSAKey
if t, err = srv.RSAKeyOrigin(c); err != nil {
log.Error("service.RSAKeyOrigin() error(%v)", err)
c.JSON(nil, err)
return
}
c.JSON(t, nil)
}
func getKey(c *bm.Context) {
c.JSON(srv.RSAKey(c), nil)
}
func getKeyProxy(c *bm.Context) {
if srv.Proxy(c) {
getKeyOrigin(c)
return
}
getKey(c)
}
func renewToken(c *bm.Context) {
var (
err error
params = c.Request.Form
accessKey = params.Get("access_key")
from = params.Get("from")
)
var r *model.RenewToken
if r, err = srv.RenewToken(c, accessKey, from); err != nil {
log.Error("service.RenewToken() error(%v)", err)
res := map[string]interface{}{}
if err == service.ErrDispatcherError {
res["message"] = err.Error()
}
c.JSONMap(res, err)
return
}
c.JSON(r, nil)
}

View File

@ -0,0 +1,62 @@
package http
import (
"strconv"
"go-common/app/service/main/passport-game/model"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
func loginOrigin(c *bm.Context) {
var (
err error
t *model.LoginToken
params = c.Request.Form
cookie = c.Request.Header.Get("Cookie")
)
if t, err = srv.LoginOrigin(c, params.Encode(), cookie); err != nil {
log.Error("service.LoginOrigin(%s, %s) error(%v)", params.Encode(), cookie, err)
c.JSON(nil, err)
return
}
c.JSON(t, nil)
}
func login(c *bm.Context) {
var (
err error
subid = int64(0)
params = c.Request.Form
subidStr = params.Get("subid")
userid = params.Get("userid")
rsaPwd = params.Get("pwd")
)
if subidStr != "" {
if subid, err = strconv.ParseInt(subidStr, 10, 32); err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
}
app, ok := c.Get("app")
if !ok {
c.JSON(nil, ecode.AppKeyInvalid)
return
}
t, err := srv.Login(c, app.(*model.App), int32(subid), userid, rsaPwd)
if err != nil {
log.Error("service.Login() error(%v)", err)
c.JSON(nil, err)
return
}
c.JSON(t, err)
}
func loginProxy(c *bm.Context) {
if srv.Proxy(c) {
loginOrigin(c)
return
}
login(c)
}

View File

@ -0,0 +1,67 @@
package http
import (
"go-common/app/service/main/passport-game/model"
bm "go-common/library/net/http/blademaster"
"go-common/library/net/metadata"
)
func regV3(c *bm.Context) {
var argRegV3 = new(model.ArgRegV3)
err := c.Bind(argRegV3)
if err != nil {
return
}
var cookie = c.Request.Header.Get("Cookie")
c.JSON(srv.RegV3(c, model.TdoRegV3{Arg: *argRegV3, IP: metadata.String(c, metadata.RemoteIP), Cookie: cookie}))
}
func regV2(c *bm.Context) {
var argRegV2 = new(model.ArgRegV2)
err := c.Bind(argRegV2)
if err != nil {
return
}
var cookie = c.Request.Header.Get("Cookie")
c.JSON(srv.RegV2(c, model.TdoRegV2{Arg: *argRegV2, IP: metadata.String(c, metadata.RemoteIP), Cookie: cookie}))
}
func reg(c *bm.Context) {
var argReg = new(model.ArgReg)
err := c.Bind(argReg)
if err != nil {
return
}
var cookie = c.Request.Header.Get("Cookie")
c.JSON(srv.Reg(c, model.TdoReg{Arg: *argReg, IP: metadata.String(c, metadata.RemoteIP), Cookie: cookie}))
}
func byTel(c *bm.Context) {
var argByTel = new(model.ArgByTel)
err := c.Bind(argByTel)
if err != nil {
return
}
var cookie = c.Request.Header.Get("Cookie")
c.JSON(srv.ByTel(c, model.TdoByTel{Arg: *argByTel, IP: metadata.String(c, metadata.RemoteIP), Cookie: cookie}))
}
func captcha(c *bm.Context) {
c.JSON(srv.Captcha(c, metadata.String(c, metadata.RemoteIP)))
}
func sendSms(c *bm.Context) {
var sendSmsp = new(model.SendSms)
berr := c.Bind(sendSmsp)
if berr != nil {
return
}
var cookie = c.Request.Header.Get("Cookie")
err := srv.SendSms(c, model.TdoSendSms{Arg: *sendSmsp, IP: metadata.String(c, metadata.RemoteIP), Cookie: cookie})
c.JSON(nil, err)
}

View File

@ -0,0 +1,88 @@
package http
import (
"bytes"
"crypto/md5"
"encoding/hex"
"net/url"
"sort"
"strings"
"go-common/app/service/main/passport-game/model"
"go-common/app/service/main/passport-game/service"
"go-common/library/ecode"
bm "go-common/library/net/http/blademaster"
)
// VerifySign verify sign.
func verifySign(c *bm.Context, s *service.Service) (res *model.App, err error) {
var (
r = c.Request
query = r.Form
)
if r.Method == "POST" {
// Give priority to sign in url query, otherwise check sign in post form.
p := c.Request.URL.Query()
if p.Get("sign") != "" {
query = p
}
}
if query.Get("ts") == "" {
err = ecode.RequestErr
return
}
appKey := query.Get("appkey")
if appKey == "" {
err = ecode.RequestErr
return
}
app, ok := s.APP(appKey)
if !ok {
err = ecode.AppKeyInvalid
return
}
secret := app.AppSecret
tmp := encodeQuery(query)
if strings.IndexByte(tmp, '+') > -1 {
tmp = strings.Replace(tmp, "+", "%20", -1)
}
mh := md5.Sum([]byte(strings.ToLower(tmp) + secret))
sign := query.Get("sign")
if hex.EncodeToString(mh[:]) != sign {
mh1 := md5.Sum([]byte(tmp + secret))
if hex.EncodeToString(mh1[:]) != sign {
err = ecode.SignCheckErr
}
}
res = app
return
}
// encodeQuery encodes the values into ``URL encoded'' form ("bar=baz&foo=quux") sorted by key.
// NOTE: sign ignored!!!
func encodeQuery(v url.Values) string {
if v == nil {
return ""
}
var buf bytes.Buffer
keys := make([]string, 0, len(v))
for k := range v {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
if k == "sign" {
continue
}
vs := v[k]
prefix := url.QueryEscape(k) + "="
for _, v := range vs {
if buf.Len() > 0 {
buf.WriteByte('&')
}
buf.WriteString(prefix)
buf.WriteString(url.QueryEscape(v))
}
}
return buf.String()
}

View File

@ -0,0 +1,58 @@
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 = [
"cloud.go",
"model.go",
"open.go",
],
embed = [":model_go_proto"],
importpath = "go-common/app/service/main/passport-game/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 = ["model.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/passport-game/model",
proto = ":model_proto",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = ["@com_github_gogo_protobuf//gogoproto:go_default_library"],
)

View File

@ -0,0 +1,7 @@
package model
// RegionInfo region item.
type RegionInfo struct {
Region string `json:"region"`
TokenSuffix string `json:"token_suffix"`
}

View File

@ -0,0 +1,212 @@
package model
import (
"crypto/md5"
"encoding/hex"
"fmt"
"strconv"
xtime "go-common/library/time"
)
const (
// EmptyFace empty face
EmptyFace = "http://static.hdslb.com/images/member/noface.gif"
_cloudSalt = "bi_clould_tencent_01"
_leak = 1
)
// FullFace account full face.
func (m *Info) FullFace() string {
if m.Face == "" {
return EmptyFace
}
return fmt.Sprintf("http://i%d.hdslb.com%s", m.Mid%3, m.Face)
}
// Token token resp.
type Token struct {
Mid int64 `json:"mid"`
AppID int32 `json:"appid"`
AccessToken string `json:"access_key"`
CreateAt int64 `json:"create_at"`
UserID string `json:"userid"`
Uname string `json:"uname"`
Expires int64 `json:"expires"`
Permission string `json:"permission"`
}
// LoginToken login token.
type LoginToken struct {
Mid int64 `json:"mid"`
AccessKey string `json:"access_key"`
Expires int64 `json:"expires"`
}
// RSAKey rsa key.
type RSAKey struct {
Hash string `json:"hash"`
Key string `json:"key"`
}
// RenewToken renew token resp.
type RenewToken struct {
Expires int64 `json:"expires"`
}
// AsoAccount aso account.
type AsoAccount struct {
Mid int64 `json:"mid"`
UserID string `json:"userid"`
Uname string `json:"uname"`
Pwd string `json:"pwd"`
Salt string `json:"salt"`
Email *string `json:"email"`
Tel *string `json:"tel"`
CountryID int64 `json:"country_id"`
MobileVerified int8 `json:"mobile_verified"`
Isleak int8 `json:"isleak"`
Ctime xtime.Time `json:"-"`
Mtime xtime.Time `json:"-"`
}
// ResRegV3 ResRegV3
type ResRegV3 struct {
Mid int `json:"mid"`
}
// ResRegV2 ResRegV2
type ResRegV2 struct {
Mid int `json:"mid"`
AccessKey string `json:"accessKey"`
}
// ResReg ResReg
type ResReg struct {
Mid int `json:"mid"`
}
// ResByTel ResByTel
type ResByTel struct {
Mid int `json:"mid"`
AccessKey string `json:"accessKey"`
}
// ResCaptcha ResCaptcha
type ResCaptcha struct {
Code int `json:"code"`
Message string `json:"message"`
Data CaptchaData `json:"data"`
}
// CaptchaData CaptchaData
type CaptchaData struct {
Token string `json:"token"`
URL string `json:"url"`
}
// ArgRegV3 ArgRegV3
type ArgRegV3 struct {
User string `form:"user" validate:"required"`
Pwd string `form:"pwd" validate:"required"`
Captcha string `form:"captcha"`
Ctoken string `form:"ctoken"`
}
// ArgRegV2 ArgRegV2
type ArgRegV2 struct {
Captcha string `form:"captcha"`
Ctoken string `form:"ctoken"`
}
// ArgReg ArgReg
type ArgReg struct {
Email string `form:"email" validate:"required"`
Userpwd string `form:"pwd" validate:"required"`
User string `form:"user" validate:"required"`
}
// ArgByTel ArgByTel
type ArgByTel struct {
Tel string `form:"tel" validate:"required"`
Uname string `form:"user" validate:"required"`
Userpwd string `form:"pwd" validate:"required"`
CountryID string `form:"country_id" validate:"required"`
Captcha string `form:"captcha" validate:"required"`
}
// SendSms SendSms
type SendSms struct {
Tel string `form:"tel" validate:"required"`
CountryID string `form:"country_id" validate:"required"`
Captcha string `form:"captcha" `
Ctoken string `form:"ctoken" `
ResetPwd bool `form:"reset_pwd" `
}
// TdoRegV3 TdoRegV3
type TdoRegV3 struct {
Arg ArgRegV3
Cookie string
IP string
}
// TdoRegV2 TdoRegV2
type TdoRegV2 struct {
Arg ArgRegV2
Cookie string
IP string
}
// TdoReg TdoReg
type TdoReg struct {
Arg ArgReg
Cookie string
IP string
}
// TdoByTel TdoByTel
type TdoByTel struct {
Arg ArgByTel
Cookie string
IP string
}
// TdoSendSms TdoSendSms
type TdoSendSms struct {
Arg SendSms
Cookie string
IP string
}
// Leak leak.
func (a *AsoAccount) Leak() bool {
return a.Isleak == _leak
}
// DefaultHash hash a plain text using default salt.
func DefaultHash(plaintext string) string {
return doHash(plaintext, _cloudSalt)
}
func doHash(plaintext, salt string) string {
if plaintext == "" {
return ""
}
hash := md5.New()
hash.Write([]byte(plaintext))
hash.Write([]byte(salt))
md := hash.Sum(nil)
return hex.EncodeToString(md)
}
// DefaultUserID get default user id.
func DefaultUserID(mid int64) string {
return "用户" + strconv.FormatInt(mid, 10)
}
// DefaultUname get default uname.
func DefaultUname(mid int64) string {
return "用户" + strconv.FormatInt(mid, 10)
}

View File

@ -0,0 +1,888 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: model.proto
/*
Package model is a generated protocol buffer package.
It is generated from these files:
model.proto
It has these top-level messages:
Info
Perm
*/
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
// Info account info.
type Info struct {
Mid int64 `protobuf:"varint,1,opt,name=Mid,proto3" json:"mid"`
UserID string `protobuf:"bytes,2,opt,name=UserID,proto3" json:"userid"`
Uname string `protobuf:"bytes,3,opt,name=Uname,proto3" json:"uname"`
Face string `protobuf:"bytes,4,opt,name=Face,proto3" json:"face"`
HasEmail bool `protobuf:"varint,5,opt,name=HasEmail,proto3" json:"has_email"`
HasTel bool `protobuf:"varint,6,opt,name=HasTel,proto3" json:"has_tel"`
}
func (m *Info) Reset() { *m = Info{} }
func (m *Info) String() string { return proto.CompactTextString(m) }
func (*Info) ProtoMessage() {}
func (*Info) Descriptor() ([]byte, []int) { return fileDescriptorModel, []int{0} }
func (m *Info) GetMid() int64 {
if m != nil {
return m.Mid
}
return 0
}
func (m *Info) GetUserID() string {
if m != nil {
return m.UserID
}
return ""
}
func (m *Info) GetUname() string {
if m != nil {
return m.Uname
}
return ""
}
func (m *Info) GetFace() string {
if m != nil {
return m.Face
}
return ""
}
func (m *Info) GetHasEmail() bool {
if m != nil {
return m.HasEmail
}
return false
}
func (m *Info) GetHasTel() bool {
if m != nil {
return m.HasTel
}
return false
}
// Perm token.
type Perm struct {
Mid int64 `protobuf:"varint,1,opt,name=Mid,proto3" json:"mid"`
AppID int32 `protobuf:"varint,2,opt,name=AppID,proto3" json:"appid"`
AppSubID int32 `protobuf:"varint,3,opt,name=AppSubID,proto3" json:"app_subid"`
AccessToken string `protobuf:"bytes,4,opt,name=AccessToken,proto3" json:"access_token"`
RefreshToken string `protobuf:"bytes,5,opt,name=RefreshToken,proto3" json:"refresh_token"`
CreateAt int64 `protobuf:"varint,6,opt,name=CreateAt,proto3" json:"create_at"`
Expires int64 `protobuf:"varint,7,opt,name=Expires,proto3" json:"expires"`
}
func (m *Perm) Reset() { *m = Perm{} }
func (m *Perm) String() string { return proto.CompactTextString(m) }
func (*Perm) ProtoMessage() {}
func (*Perm) Descriptor() ([]byte, []int) { return fileDescriptorModel, []int{1} }
func (m *Perm) GetMid() int64 {
if m != nil {
return m.Mid
}
return 0
}
func (m *Perm) GetAppID() int32 {
if m != nil {
return m.AppID
}
return 0
}
func (m *Perm) GetAppSubID() int32 {
if m != nil {
return m.AppSubID
}
return 0
}
func (m *Perm) GetAccessToken() string {
if m != nil {
return m.AccessToken
}
return ""
}
func (m *Perm) GetRefreshToken() string {
if m != nil {
return m.RefreshToken
}
return ""
}
func (m *Perm) GetCreateAt() int64 {
if m != nil {
return m.CreateAt
}
return 0
}
func (m *Perm) GetExpires() int64 {
if m != nil {
return m.Expires
}
return 0
}
func init() {
proto.RegisterType((*Info)(nil), "model.Info")
proto.RegisterType((*Perm)(nil), "model.Perm")
}
func (m *Info) 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 *Info) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.Mid != 0 {
dAtA[i] = 0x8
i++
i = encodeVarintModel(dAtA, i, uint64(m.Mid))
}
if len(m.UserID) > 0 {
dAtA[i] = 0x12
i++
i = encodeVarintModel(dAtA, i, uint64(len(m.UserID)))
i += copy(dAtA[i:], m.UserID)
}
if len(m.Uname) > 0 {
dAtA[i] = 0x1a
i++
i = encodeVarintModel(dAtA, i, uint64(len(m.Uname)))
i += copy(dAtA[i:], m.Uname)
}
if len(m.Face) > 0 {
dAtA[i] = 0x22
i++
i = encodeVarintModel(dAtA, i, uint64(len(m.Face)))
i += copy(dAtA[i:], m.Face)
}
if m.HasEmail {
dAtA[i] = 0x28
i++
if m.HasEmail {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i++
}
if m.HasTel {
dAtA[i] = 0x30
i++
if m.HasTel {
dAtA[i] = 1
} else {
dAtA[i] = 0
}
i++
}
return i, nil
}
func (m *Perm) 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 *Perm) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.Mid != 0 {
dAtA[i] = 0x8
i++
i = encodeVarintModel(dAtA, i, uint64(m.Mid))
}
if m.AppID != 0 {
dAtA[i] = 0x10
i++
i = encodeVarintModel(dAtA, i, uint64(m.AppID))
}
if m.AppSubID != 0 {
dAtA[i] = 0x18
i++
i = encodeVarintModel(dAtA, i, uint64(m.AppSubID))
}
if len(m.AccessToken) > 0 {
dAtA[i] = 0x22
i++
i = encodeVarintModel(dAtA, i, uint64(len(m.AccessToken)))
i += copy(dAtA[i:], m.AccessToken)
}
if len(m.RefreshToken) > 0 {
dAtA[i] = 0x2a
i++
i = encodeVarintModel(dAtA, i, uint64(len(m.RefreshToken)))
i += copy(dAtA[i:], m.RefreshToken)
}
if m.CreateAt != 0 {
dAtA[i] = 0x30
i++
i = encodeVarintModel(dAtA, i, uint64(m.CreateAt))
}
if m.Expires != 0 {
dAtA[i] = 0x38
i++
i = encodeVarintModel(dAtA, i, uint64(m.Expires))
}
return i, nil
}
func encodeVarintModel(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 *Info) Size() (n int) {
var l int
_ = l
if m.Mid != 0 {
n += 1 + sovModel(uint64(m.Mid))
}
l = len(m.UserID)
if l > 0 {
n += 1 + l + sovModel(uint64(l))
}
l = len(m.Uname)
if l > 0 {
n += 1 + l + sovModel(uint64(l))
}
l = len(m.Face)
if l > 0 {
n += 1 + l + sovModel(uint64(l))
}
if m.HasEmail {
n += 2
}
if m.HasTel {
n += 2
}
return n
}
func (m *Perm) Size() (n int) {
var l int
_ = l
if m.Mid != 0 {
n += 1 + sovModel(uint64(m.Mid))
}
if m.AppID != 0 {
n += 1 + sovModel(uint64(m.AppID))
}
if m.AppSubID != 0 {
n += 1 + sovModel(uint64(m.AppSubID))
}
l = len(m.AccessToken)
if l > 0 {
n += 1 + l + sovModel(uint64(l))
}
l = len(m.RefreshToken)
if l > 0 {
n += 1 + l + sovModel(uint64(l))
}
if m.CreateAt != 0 {
n += 1 + sovModel(uint64(m.CreateAt))
}
if m.Expires != 0 {
n += 1 + sovModel(uint64(m.Expires))
}
return n
}
func sovModel(x uint64) (n int) {
for {
n++
x >>= 7
if x == 0 {
break
}
}
return n
}
func sozModel(x uint64) (n int) {
return sovModel(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *Info) 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 ErrIntOverflowModel
}
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: Info: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Info: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Mid", wireType)
}
m.Mid = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowModel
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Mid |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field UserID", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowModel
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthModel
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.UserID = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Uname", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowModel
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthModel
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Uname = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Face", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowModel
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthModel
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Face = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 5:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field HasEmail", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowModel
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.HasEmail = bool(v != 0)
case 6:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field HasTel", wireType)
}
var v int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowModel
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
v |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.HasTel = bool(v != 0)
default:
iNdEx = preIndex
skippy, err := skipModel(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthModel
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *Perm) 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 ErrIntOverflowModel
}
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: Perm: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Perm: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Mid", wireType)
}
m.Mid = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowModel
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Mid |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field AppID", wireType)
}
m.AppID = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowModel
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.AppID |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 3:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field AppSubID", wireType)
}
m.AppSubID = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowModel
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.AppSubID |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field AccessToken", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowModel
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthModel
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.AccessToken = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 5:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field RefreshToken", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowModel
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthModel
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.RefreshToken = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 6:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field CreateAt", wireType)
}
m.CreateAt = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowModel
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.CreateAt |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 7:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field Expires", wireType)
}
m.Expires = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowModel
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
m.Expires |= (int64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipModel(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthModel
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipModel(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, ErrIntOverflowModel
}
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, ErrIntOverflowModel
}
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, ErrIntOverflowModel
}
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, ErrInvalidLengthModel
}
return iNdEx, nil
case 3:
for {
var innerWire uint64
var start int = iNdEx
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowModel
}
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 := skipModel(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 (
ErrInvalidLengthModel = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowModel = fmt.Errorf("proto: integer overflow")
)
func init() { proto.RegisterFile("model.proto", fileDescriptorModel) }
var fileDescriptorModel = []byte{
// 409 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x92, 0x4f, 0x8e, 0xd3, 0x30,
0x14, 0xc6, 0xc9, 0xe4, 0x4f, 0x5b, 0x77, 0x46, 0x1a, 0xbc, 0x0a, 0x08, 0xd5, 0x55, 0x11, 0x52,
0x59, 0x30, 0x23, 0x81, 0x38, 0x40, 0xcb, 0x0c, 0x9a, 0x2e, 0x90, 0x90, 0x99, 0xae, 0x2b, 0x27,
0x79, 0x6d, 0x23, 0x92, 0xda, 0xb2, 0x13, 0x89, 0xa3, 0x70, 0x06, 0x4e, 0xc2, 0x92, 0x05, 0x6b,
0x0b, 0x95, 0x9d, 0x4f, 0x81, 0xf2, 0x1c, 0x2a, 0xd8, 0xcc, 0x2e, 0xef, 0xf7, 0xfb, 0x9e, 0xf4,
0x3d, 0x2b, 0x64, 0x5c, 0xcb, 0x02, 0xaa, 0x2b, 0xa5, 0x65, 0x23, 0x69, 0x8c, 0xc3, 0xd3, 0x57,
0xbb, 0xb2, 0xd9, 0xb7, 0xd9, 0x55, 0x2e, 0xeb, 0xeb, 0x9d, 0xdc, 0xc9, 0x6b, 0xb4, 0x59, 0xbb,
0xc5, 0x09, 0x07, 0xfc, 0xf2, 0x5b, 0xb3, 0x9f, 0x01, 0x89, 0x56, 0x87, 0xad, 0xa4, 0x4f, 0x48,
0xf8, 0xa1, 0x2c, 0xd2, 0x60, 0x1a, 0xcc, 0xc3, 0xe5, 0xc0, 0x59, 0x16, 0xd6, 0x65, 0xc1, 0x3b,
0x46, 0x67, 0x24, 0x59, 0x1b, 0xd0, 0xab, 0x9b, 0xf4, 0x6c, 0x1a, 0xcc, 0x47, 0x4b, 0xe2, 0x2c,
0x4b, 0x5a, 0x03, 0xba, 0x2c, 0x78, 0x6f, 0x28, 0x23, 0xf1, 0xfa, 0x20, 0x6a, 0x48, 0x43, 0x8c,
0x8c, 0x9c, 0x65, 0x71, 0xdb, 0x01, 0xee, 0x39, 0x7d, 0x46, 0xa2, 0xf7, 0x22, 0x87, 0x34, 0x42,
0x3f, 0x74, 0x96, 0x45, 0x5b, 0x91, 0x03, 0x47, 0x4a, 0x5f, 0x92, 0xe1, 0x9d, 0x30, 0xb7, 0xb5,
0x28, 0xab, 0x34, 0x9e, 0x06, 0xf3, 0xe1, 0xf2, 0xc2, 0x59, 0x36, 0xda, 0x0b, 0xb3, 0x81, 0x0e,
0xf2, 0x93, 0xa6, 0xcf, 0x49, 0x72, 0x27, 0xcc, 0x3d, 0x54, 0x69, 0x82, 0xc1, 0xb1, 0xb3, 0x6c,
0xd0, 0x05, 0x1b, 0xa8, 0x78, 0xaf, 0x66, 0xdf, 0xce, 0x48, 0xf4, 0x11, 0x74, 0xfd, 0xd0, 0x59,
0x8c, 0xc4, 0x0b, 0xa5, 0xfa, 0xab, 0x62, 0x5f, 0x59, 0x28, 0x55, 0x16, 0xdc, 0xf3, 0xae, 0xd4,
0x42, 0xa9, 0x4f, 0x6d, 0xb6, 0xba, 0xc1, 0xb3, 0x62, 0x5f, 0x4a, 0x28, 0xb5, 0x31, 0x6d, 0x56,
0x16, 0xfc, 0xa4, 0xe9, 0x6b, 0x32, 0x5e, 0xe4, 0x39, 0x18, 0x73, 0x2f, 0x3f, 0xc3, 0xa1, 0x3f,
0xf2, 0xd2, 0x59, 0x76, 0x2e, 0x10, 0x6f, 0x9a, 0x8e, 0xf3, 0x7f, 0x43, 0xf4, 0x2d, 0x39, 0xe7,
0xb0, 0xd5, 0x60, 0xf6, 0x7e, 0x29, 0xc6, 0xa5, 0xc7, 0xce, 0xb2, 0x0b, 0xed, 0x79, 0xbf, 0xf5,
0x5f, 0xac, 0x6b, 0xf5, 0x4e, 0x83, 0x68, 0x60, 0xd1, 0xe0, 0x0b, 0x84, 0xbe, 0x55, 0x8e, 0x6c,
0x23, 0x1a, 0x7e, 0xd2, 0xf4, 0x05, 0x19, 0xdc, 0x7e, 0x51, 0xa5, 0x06, 0x93, 0x0e, 0x30, 0x89,
0x6f, 0x05, 0x1e, 0xf1, 0xbf, 0x6e, 0x79, 0xf9, 0xfd, 0x38, 0x09, 0x7e, 0x1c, 0x27, 0xc1, 0xaf,
0xe3, 0x24, 0xf8, 0xfa, 0x7b, 0xf2, 0x28, 0x4b, 0xf0, 0xe7, 0x78, 0xf3, 0x27, 0x00, 0x00, 0xff,
0xff, 0x4a, 0x98, 0xa7, 0x40, 0x61, 0x02, 0x00, 0x00,
}

View File

@ -0,0 +1,26 @@
syntax = "proto3";
package model;
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
// Info account info.
message Info {
int64 Mid = 1 [ (gogoproto.jsontag) = "mid" ];
string UserID = 2 [ (gogoproto.jsontag) = "userid" ];
string Uname = 3 [ (gogoproto.jsontag) = "uname" ];
string Face = 4 [ (gogoproto.jsontag) = "face" ];
bool HasEmail = 5 [ (gogoproto.jsontag) = "has_email" ];
bool HasTel = 6 [ (gogoproto.jsontag) = "has_tel" ];
}
// Perm token.
message Perm {
int64 Mid = 1 [ (gogoproto.jsontag) = "mid" ];
int32 AppID = 2 [ (gogoproto.jsontag) = "appid" ];
int32 AppSubID = 3 [ (gogoproto.jsontag) = "app_subid" ];
string AccessToken = 4 [ (gogoproto.jsontag) = "access_token" ];
string RefreshToken = 5 [ (gogoproto.jsontag) = "refresh_token" ];
int64 CreateAt = 6 [ (gogoproto.jsontag) = "create_at" ];
int64 Expires = 7 [ (gogoproto.jsontag) = "expires" ];
}

View File

@ -0,0 +1,8 @@
package model
// App app info.
type App struct {
AppID int32 `json:"appid"`
AppKey string `json:"appkey"`
AppSecret string `json:"app_secret"`
}

View File

@ -0,0 +1,5 @@
#! /bin/sh
# proto.sh
gopath=$GOPATH/src
gogopath=$GOPATH/src/go-common/vendor/github.com/gogo/protobuf
protoc --gofast_out=. --proto_path=$gopath:$gogopath:. *.proto

View File

@ -0,0 +1,80 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"account.go",
"cache.go",
"md5.go",
"passport.go",
"passport_key.go",
"passport_login.go",
"passport_oauth.go",
"passport_reg.go",
"passport_renew_token.go",
"region.go",
"rsa.go",
"rsa_time_hash.go",
"service.go",
],
importpath = "go-common/app/service/main/passport-game/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/passport-game/conf:go_default_library",
"//app/service/main/passport-game/dao:go_default_library",
"//app/service/main/passport-game/model:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/stat:go_default_library",
"//library/stat/prom:go_default_library",
"//library/sync/errgroup:go_default_library",
"//vendor/github.com/satori/go.uuid:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"account_test.go",
"md5_test.go",
"passport_key_test.go",
"passport_login_test.go",
"passport_oauth_test.go",
"passport_reg_test.go",
"passport_renew_token_test.go",
"passport_test.go",
"region_test.go",
"rsa_test.go",
"rsa_time_hash_test.go",
"service_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/passport-game/conf:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//vendor/github.com/satori/go.uuid: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,74 @@
package service
import (
"context"
"go-common/app/service/main/passport-game/model"
"go-common/library/sync/errgroup"
)
// MyInfo get user's info by token.
func (s *Service) MyInfo(c context.Context, app *model.App, accessKey string) (*model.Info, error) {
ti, err := s.thinOauth(c, app, accessKey)
if err != nil {
return nil, err
}
return s.Info(c, ti.Mid), nil
}
// Info get user's info by mid.
func (s *Service) Info(c context.Context, mid int64) (res *model.Info) {
var err error
cache := true
if res, err = s.d.InfoCache(c, mid); err != nil {
err = nil
cache = false
} else if res != nil {
return
}
var userid, uname, face string
var email, tel *string
eg, errCtx := errgroup.WithContext(c)
eg.Go(func() (err error) {
accInfo, err := s.d.AccountInfo(errCtx, mid)
if err != nil || accInfo == nil {
userid = model.DefaultUserID(mid)
uname = model.DefaultUname(mid)
return
}
userid = accInfo.UserID
uname = accInfo.Uname
email = accInfo.Email
tel = accInfo.Tel
return
})
eg.Go(func() (err error) {
memInfo, err := s.d.MemberInfo(errCtx, mid)
if err != nil || memInfo == nil {
face = model.EmptyFace
return
}
face = memInfo.FullFace()
return
})
eg.Wait()
info := &model.Info{
Mid: mid,
UserID: userid,
Uname: uname,
Face: face,
}
if email != nil {
info.HasEmail = true
}
if tel != nil {
info.HasTel = true
}
if cache {
s.addCache(func() {
s.d.SetInfoCache(context.Background(), info)
})
}
res = info
return
}

View File

@ -0,0 +1,28 @@
package service
import (
"context"
"encoding/json"
"testing"
)
const (
_gameAppKey = "d4761645d1632e8c"
)
// TestService_MyInfo oauth via origin.
func TestService_MyInfo(t *testing.T) {
once.Do(startService)
ak := "4de8aecfafc7f91cb650d6371efb1b63"
expectMid := int64(110000139)
if res, err := s.MyInfo(context.TODO(), s.appMap[_gameAppKey], ak); err != nil {
t.Errorf("s.MyInfo() error(%v)", err)
t.FailNow()
} else if res == nil || res.Mid != expectMid {
t.Errorf("res is not correct, expected res with mid %d but got %v", expectMid, res)
t.FailNow()
} else {
str, _ := json.Marshal(res)
t.Logf("res: %s", str)
}
}

View File

@ -0,0 +1,17 @@
package service
import (
"context"
"go-common/app/service/main/passport-game/model"
)
// TokenPBCache get token pb cache.
func (s *Service) TokenPBCache(c context.Context, key string) (res *model.Perm, err error) {
return s.d.TokenPBCache(c, key)
}
// InfoPBCache get info pb cache.
func (s *Service) InfoPBCache(c context.Context, key string) (res *model.Info, err error) {
return s.d.InfoPBCache(c, key)
}

View File

@ -0,0 +1,27 @@
package service
import (
"crypto/md5"
"encoding/hex"
"math/big"
)
func md5Hex(s string) string {
sum := md5.Sum([]byte(s))
return hex.EncodeToString(sum[:])
}
// MD52IntStr converts MD5 checksum bytes to big int string in base 10.
func MD52IntStr(md5d []byte) (res string) {
b := big.NewInt(0)
b.SetBytes(md5d)
res = b.Text(10)
return
}
// IntStr2Md5 converts big int string in base 10 to MD5 checksum bytes.
func IntStr2Md5(intStr string) (res []byte) {
b := big.NewInt(0)
b.SetString(intStr, 10)
return b.Bytes()
}

View File

@ -0,0 +1,21 @@
package service
import (
"bytes"
"crypto/md5"
"fmt"
"testing"
)
func TestMD52IntStr(t *testing.T) {
md5d := md5.Sum([]byte("foo"))
intStr := MD52IntStr(md5d[:])
md5dAfter := IntStr2Md5(intStr)
if !bytes.Equal(md5d[:], md5dAfter) {
t.FailNow()
}
}
func TestClout(t *testing.T) {
fmt.Println(md5Hex(fmt.Sprintf("%s>>BiLiSaLt<<%s", md5Hex("prFP8dF2z1"), "bBTXzlsT")))
}

View File

@ -0,0 +1,42 @@
package service
import (
"context"
"errors"
"go-common/app/service/main/passport-game/model"
)
const (
_expireSeconds = 2592000 // 30 days
_gameAdditionalExpireSeconds = 1296000 // 15 days
)
var (
// ErrDispatcherError dispatcher error
ErrDispatcherError = errors.New("dispatcher route map is error")
)
func (s *Service) tokenInfo(c context.Context, accessKey string) (token *model.Perm, err error) {
cache := true
if token, err = s.d.TokenCache(c, accessKey); err != nil {
err = nil
cache = false
} else if token != nil {
return
}
if token, err = s.d.Token(c, accessKey); err != nil {
return
}
if cache && token != nil {
s.addCache(func() {
s.d.SetTokenCache(context.TODO(), token)
})
}
return
}
// Proxy if login and getKey via model api.
func (s *Service) Proxy(c context.Context) (res bool) {
return s.proxy
}

View File

@ -0,0 +1,47 @@
package service
import (
"context"
"time"
"go-common/app/service/main/passport-game/model"
)
const (
_originPubKey = "-----BEGIN PUBLIC KEY-----\n" +
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCdScM09sZJqFPX7bvmB2y6i08J\n" +
"bHsa0v4THafPbJN9NoaZ9Djz1LmeLkVlmWx1DwgHVW+K7LVWT5FV3johacVRuV98\n" +
"37+RNntEK6SE82MPcl7fA++dmW2cLlAjsIIkrX+aIvvSGCuUfcWpWFy3YVDqhuHr\n" +
"NDjdNcaefJIQHMW+sQIDAQAB\n" +
"-----END PUBLIC KEY-----\n"
_originPrivKey = "-----BEGIN PRIVATE KEY-----\n" +
"MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAJ1JwzT2xkmoU9ft\n" +
"u+YHbLqLTwlsexrS/hMdp89sk302hpn0OPPUuZ4uRWWZbHUPCAdVb4rstVZPkVXe\n" +
"OiFpxVG5X3zfv5E2e0QrpITzYw9yXt8D752ZbZwuUCOwgiStf5oi+9IYK5R9xalY\n" +
"XLdhUOqG4es0ON01xp58khAcxb6xAgMBAAECgYAsBeQ8I8HWBeYJrsGDnZpiD/G8\n" +
"On+uP1XbtdYtKT+SsTs1RfTW0jhtvJex2yJPFTjzDIeew6fxk22jMgLlLTyLtc+H\n" +
"LFmNt6/5DIxeSslx0cZOJW2w1KLyzPBIVQ+q1rAu4wZx4LSTFzAHQGWkGH3352Nj\n" +
"40GIMOMOLrOReb8/rQJBAM4S8mChP9NAWvjSyQY4jqHQsCmcDeV1Tuwo5jxeMMZ5\n" +
"YSrtwEEaLN4mkvpMeQR60RtjdJXxfySJY0lF/e5RZ7sCQQDDZQjUmry41Ar6uSGj\n" +
"OrZADOSmqZy0qCijgthkN2Gblx9eyFFMFcakJECF/m2zUo5MeqKu5RTDXBZt0b3l\n" +
"JV6DAkEAnIv0KMgWbmsDMOcf42PvpqmcSd/NBrU5AVqInO+I6h2nXS9Dz7EMyK5R\n" +
"FWgmvup2E/JXzNiql5zvGejb4MFipQJAVScl5wmcb2wxcLzXtPw0SsuTpjJK0cxr\n" +
"EX9HcL1V82mzySnBjEf9LrGB0SNliX3T9+6GEXRSTSVHvQpoGIHlowJBAKJBTxKi\n" +
"9ypIdK1mA7kw8+g+YdXliov5B2MMe1yaGyGjz3YGQ8N1YLBK6Yp4KOwodFurmgcX\n" +
"ozLanqOwPdNW1Nk=\n" +
"-----END PRIVATE KEY-----\n"
)
// RSAKeyOrigin get rsa key via model api.
func (s *Service) RSAKeyOrigin(c context.Context) (res *model.RSAKey, err error) {
return s.d.RSAKeyOrigin(c)
}
// RSAKey get cloud rsa pub key and seconds ts hash.
func (s *Service) RSAKey(c context.Context) *model.RSAKey {
return &model.RSAKey{
Hash: TsSeconds2Hash(time.Now().Unix()),
Key: _originPubKey,
}
}

View File

@ -0,0 +1,27 @@
package service
import (
"context"
"encoding/json"
"testing"
)
func TestService_RSAKey(t *testing.T) {
once.Do(startService)
originRSA, err := s.RSAKeyOrigin(context.TODO())
if err != nil {
t.Errorf("failed to get origin public key, service.RSAKeyOrigin() error(%v)", err)
t.FailNow()
} else {
str, _ := json.Marshal(originRSA)
t.Logf("cloud RSA: %s", str)
}
cloudRSA := s.RSAKey(context.TODO())
if cloudRSA.Key == originRSA.Key {
t.Errorf("cloud RSA public key cannot be equal to origin RSA public key")
t.FailNow()
} else {
str, _ := json.Marshal(cloudRSA)
t.Logf("cloud RSA: %s", str)
}
}

View File

@ -0,0 +1,215 @@
package service
import (
"context"
"encoding/base64"
"fmt"
"time"
"go-common/app/service/main/passport-game/model"
"go-common/library/ecode"
"go-common/library/log"
"github.com/satori/go.uuid"
)
const (
_tsHashLen = 16
_rsaTimeoutSeconds = 20
_asoPasswordError = -627
)
// Login login via cloud, if err occurred, via origin.
func (s *Service) Login(c context.Context, app *model.App, subid int32, userid, rsaPwd string) (res *model.LoginToken, err error) {
if userid == "" || rsaPwd == "" {
err = ecode.UsernameOrPasswordErr
return
}
cache := true
a, pwd, tsHash, err := s.checkUserData(c, userid, rsaPwd)
if err != nil {
if err == ecode.PasswordHashExpires || err == ecode.PasswordTooLeak {
return
}
err = nil
} else {
var t *model.Perm
if t, cache, err = s.saveToken(c, app.AppID, subid, a.Mid); err != nil {
err = nil
} else {
res = &model.LoginToken{
Mid: t.Mid,
AccessKey: t.AccessToken,
Expires: t.Expires,
}
return
}
}
if res, err = s.loginOrigin(c, userid, pwd, tsHash); err != nil {
return
}
if cache && res != nil {
s.d.SetTokenCache(c, &model.Perm{
Mid: res.Mid,
AppID: app.AppID,
AppSubID: subid,
AccessToken: res.AccessKey,
CreateAt: res.Expires - _expireSeconds,
Expires: res.Expires,
})
}
return
}
func (s *Service) checkUserData(c context.Context, userid, rsaPwd string) (a *model.AsoAccount, pwd, tsHash string, err error) {
if tsHash, pwd, err = s.parseRSAPwd(rsaPwd); err != nil {
return
}
if timeout(time.Now().Unix(), tsHash) {
err = ecode.PasswordHashExpires
return
}
if pwd == "" {
err = ecode.UsernameOrPasswordErr
return
}
if a, err = s.asoAccountInfo(c, userid); err != nil {
return
}
// TODO 2017.12.27 when leak business changes, update here
if a.Leak() {
err = ecode.PasswordTooLeak
return
}
if pwd == "" {
err = ecode.UsernameOrPasswordErr
return
}
if !pwdMatches(pwd, a.Salt, a.Pwd) {
err = ecode.UsernameOrPasswordErr
}
return
}
func (s *Service) parseRSAPwd(rsaPwd string) (tsHash, pwd string, err error) {
if len(rsaPwd) < 88 {
err = ecode.UsernameOrPasswordErr
return
}
var tsHashPwd string
if tsHashPwd, err = s.rsaDecrypt(rsaPwd); err != nil {
return
}
if len(tsHashPwd) < _tsHashLen {
err = ecode.UsernameOrPasswordErr
return
}
tsHash = tsHashPwd[:_tsHashLen]
pwd = tsHashPwd[_tsHashLen:]
return
}
// asoAccountInfo get user info by userid or hash.
func (s *Service) asoAccountInfo(c context.Context, userid string) (info *model.AsoAccount, err error) {
var acs []*model.AsoAccount
if acs, err = s.d.AsoAccount(c, userid, model.DefaultHash(userid)); err != nil {
return
}
if len(acs) == 0 {
err = ecode.UserNotExist
return
}
if len(acs) > 1 {
err = ecode.UserDuplicate
return
}
info = acs[0]
return
}
func (s *Service) rsaDecrypt(rsaPwd string) (res string, err error) {
rs, err := base64.StdEncoding.DecodeString(rsaPwd)
if err != nil {
log.Error("failed to base64 decode RSA pwd for cloud, error(%v)", err)
return
}
d, err := rsaDecryptPKCS8(s.cloudRSAKey.priv, rs)
if err != nil {
log.Error("failed to decrypt RSA pwd for cloud, error(%v)", err)
return
}
res = string(d)
return
}
func (s *Service) originRSAEncrypt(pwd string, timeHash string) (res string, err error) {
ed, err := rsaEncryptPKCS8(s.originPubKey, []byte(timeHash+pwd))
if err != nil {
log.Error("failed to RSA encrypt pwd for origin, error(%v)", err)
return
}
res = base64.StdEncoding.EncodeToString(ed)
return
}
func (s *Service) loginOrigin(c context.Context, userid, pwd, tsHash string) (res *model.LoginToken, err error) {
rsaPwd, err := s.originRSAEncrypt(pwd, tsHash)
if err != nil {
return
}
res, err = s.d.LoginOrigin(c, userid, rsaPwd)
if ecode.Cause(err).Code() == _asoPasswordError {
err = ecode.UsernameOrPasswordErr
}
return
}
func timeout(now int64, rsaTimeHash string) bool {
ts, err := Hash2TsSeconds(rsaTimeHash)
if err != nil {
return false
}
return now-ts > _rsaTimeoutSeconds
}
// pwdMatches check if password matches.
// NOTE: since passport did not use salt in matching password in early period,
// those accounts which registered that time and never changed
// after passport start to use salt have empty salt,
// the schema for generating password hash in passport origin is:
// if the salt is empty, take the result of md5Hex(plain) as password hash,
// else take the result of fmt.Sprintf("%s>>BiLiSaLt<<%s", md5Hex(plainPwd), salt) as password hash.
func pwdMatches(plainPwd, salt, cloudPwdHash string) bool {
if salt == "" {
return model.DefaultHash(md5Hex(plainPwd)) == cloudPwdHash
}
return model.DefaultHash(md5Hex(fmt.Sprintf("%s>>BiLiSaLt<<%s", md5Hex(plainPwd), salt))) == cloudPwdHash
}
func (s *Service) saveToken(c context.Context, appid, subid int32, mid int64) (res *model.Perm, cache bool, err error) {
cache = true
now := time.Now().Unix()
token := &model.Perm{
Mid: mid,
AppID: appid,
AppSubID: subid,
AccessToken: md5Hex(fmt.Sprintf("%d,%s", mid, uuid.NewV4().String())) + _segmentation + s.currentRegion,
CreateAt: now,
Expires: now + _expireSeconds,
}
if _, err = s.d.AddToken(c, token); err != nil {
return
}
res = token
if err = s.d.SetTokenCache(c, token); err != nil {
err = nil
cache = false
}
return
}
// LoginOrigin login via passport api.
func (s *Service) LoginOrigin(c context.Context, query, cookie string) (res *model.LoginToken, err error) {
return s.d.Login(c, query, cookie)
}

View File

@ -0,0 +1,184 @@
package service
import (
"context"
"encoding/base64"
"encoding/json"
"strings"
"sync/atomic"
"testing"
"time"
"go-common/library/log"
"github.com/satori/go.uuid"
. "github.com/smartystreets/goconvey/convey"
)
func TestPwdMatches(t *testing.T) {
Convey("check pwd match when", t, func() {
Convey("password is incorrect", func() {
Convey("salt is empty", func() {
plain := "wrongPassword"
salt := ""
cloudRsaPwd := "b602e55952dfc534e222577eee8f469e"
ok := pwdMatches(plain, salt, cloudRsaPwd)
So(ok, ShouldBeFalse)
})
Convey("salt is not empty", func() {
plain := "wrongPassword"
salt := "DC2q1ju5"
cloudRsaPwd := "3cb9ffbfd219772793d860c97a815e4b"
ok := pwdMatches(plain, salt, cloudRsaPwd)
So(ok, ShouldBeFalse)
})
})
Convey("password is correct", func() {
Convey("salt is empty", func() {
plain := "123456"
salt := ""
cloudRsaPwd := "b602e55952dfc534e222577eee8f469e"
ok := pwdMatches(plain, salt, cloudRsaPwd)
So(ok, ShouldBeTrue)
})
Convey("salt is not empty", func() {
plain := "123456"
salt := "DC2q1ju5"
cloudRsaPwd := "3cb9ffbfd219772793d860c97a815e4b"
ok := pwdMatches(plain, salt, cloudRsaPwd)
So(ok, ShouldBeTrue)
})
})
})
}
// TestService_Login_OK login ok.
func TestService_Login_OK(t *testing.T) {
once.Do(startService)
u := "game0033"
pwdPlain := "123456"
expectMid := int64(110000139)
ts := time.Now().Unix()
rsaPwd, err := s.rsaEncrypt(TsSeconds2Hash(ts), pwdPlain)
if err != nil {
t.Errorf("faied to RSA encrypt pwd and ts, rsaEncrypt(%s, %d) error(%v)", pwdPlain, ts, err)
t.FailNow()
}
if res, err := s.Login(context.TODO(), s.appMap[_gameAppKey], 0, u, rsaPwd); err != nil {
t.Errorf("service.Login() error(%v)", err)
t.FailNow()
} else if res == nil || res.Mid != expectMid {
t.Errorf("res is not correct, expected login token with mid %d but got %v", expectMid, res)
t.FailNow()
} else {
str, _ := json.Marshal(res)
t.Logf("res: %s", str)
}
}
// TestService_Login_BackOriginWhenCloudFail when cloud login not ok,
// should back origin.
func TestService_Login_BackOriginWhenCloudFail(t *testing.T) {
once.Do(startService)
u := "test_ss"
pwdPlain := "123456"
ts := time.Now().Unix()
rsaPwd, err := s.rsaEncrypt(TsSeconds2Hash(ts), pwdPlain)
if err != nil {
t.Errorf("faied to RSA encrypt pwd and ts, rsaEncrypt(%s, %d) error(%v)", pwdPlain, ts, err)
t.FailNow()
}
if _, err := s.Login(context.TODO(), s.appMap[_gameAppKey], 0, u, rsaPwd); err != nil {
t.Errorf("back origin falied, service.Login() error(%v)", err)
t.FailNow()
}
}
func TestService_LoginOrigin(t *testing.T) {
once.Do(startService)
u := "game0033"
pwdPlain := "123456"
expectMid := int64(110000139)
tsHash := TsSeconds2Hash(time.Now().Unix())
if res, err := s.loginOrigin(context.TODO(), u, pwdPlain, tsHash); err != nil {
t.Errorf("s.loginOrigin(%s, %s, %s) error(%v)", u, pwdPlain, tsHash, err)
t.FailNow()
} else if res == nil || res.Mid != expectMid {
t.Errorf("res is not correct, expected login token with mid %d but got %v", expectMid, res)
t.FailNow()
} else {
str, _ := json.Marshal(res)
t.Logf("res: %v", string(str))
}
}
func TestService_RSADecrypt(t *testing.T) {
once.Do(startService)
expect := "123456"
rsaPwd, err := s.rsaEncrypt(TsSeconds2Hash(time.Now().Unix()), expect)
if err != nil {
t.FailNow()
}
res, err := s.rsaDecrypt(rsaPwd)
if err != nil {
t.Errorf("failed to decrypt, error(%v)", err)
t.FailNow()
}
ts, _ := Hash2TsSeconds(res[:16])
plain := res[16:]
if plain != expect {
t.Errorf("expect plain %s but got %s", expect, plain)
t.FailNow()
}
t.Logf("ts hash: %s, ts: %d, plain: %s", res[:16], ts, res[16:])
}
func BenchmarkService_RSADecrypt(b *testing.B) {
once.Do(startService)
minLen := 3
maxLen := 16
num := maxLen - minLen + 1
plains := make([]string, num)
cipers := make([]string, num)
for i := 0; i < num; i++ {
u := strings.Replace(uuid.NewV4().String(), "-", "", 4)
plains[i] = u[:i+minLen]
cb, err := rsaEncryptPKCS8(s.cloudRSAKey.pub, []byte(plains[i]))
if err != nil {
b.FailNow()
}
cipers[i] = base64.StdEncoding.EncodeToString(cb)
}
atomicCnt := int64(0)
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
idx := atomic.AddInt64(&atomicCnt, 1) % int64(num)
res, err := s.rsaDecrypt(cipers[idx])
if err != nil {
b.Errorf("s.rsaDecrypt(%s) error(%v)", cipers[idx], err)
b.FailNow()
}
if res != plains[idx] {
b.Errorf("expect %s but got %s", plains[idx], res)
b.FailNow()
}
}
})
b.ReportAllocs()
}
func (s *Service) rsaEncrypt(timeHash, pwd string) (res string, err error) {
d, err := rsaEncryptPKCS8(s.cloudRSAKey.pub, []byte(timeHash+pwd))
if err != nil {
log.Error("failed to encrypt pwd, error(%v)", err)
return
}
res = base64.StdEncoding.EncodeToString(d)
return
}

View File

@ -0,0 +1,178 @@
package service
import (
"context"
"time"
"go-common/app/service/main/passport-game/model"
"go-common/library/ecode"
"go-common/library/log"
)
// Oauth oauth.
func (s *Service) Oauth(c context.Context, app *model.App, accessToken, from string) (token *model.Token, err error) {
if accessToken == "" {
err = ecode.AccessKeyErr
return
}
region, ok := region(accessToken)
if !ok {
err = ecode.AccessKeyErr
return
}
if region == s.currentRegion {
return s.currentOauth(c, accessToken)
}
if region == _origin {
token, err = s.currentOauth(c, accessToken)
} else {
token, err = s.otherOauth(c, accessToken)
}
if err == nil && token != nil && token.Mid > 0 {
return
}
if from != "" {
s.dispatcherErrStats.Incr("dispatcher_error")
err = ErrDispatcherError
return
}
return s.originOauth(c, s.oauth[region], accessToken, s.currentRegion)
}
func (s *Service) originOauth(c context.Context, uri, accessKey, from string) (*model.Token, error) {
cache := true
token, err := s.d.OriginTokenCache(c, accessKey)
if token != nil {
if token.Mid > 0 {
return token, nil
}
return nil, ecode.NoLogin
}
if err != nil {
cache = false
log.Error("Faield to get origin token cache with access key: %s: %+v", accessKey, err)
}
token, err = s.d.Oauth(c, uri, accessKey, from)
if token != nil {
// s.addCache(func() { s.d.SetOriginTokenCache(context.Background(), token) })
return token, nil
}
log.Error("Failed to oauth token by origin: %s, %s, %s: %+v", uri, accessKey, from, err)
if !cache {
return nil, err
}
if ec := ecode.Cause(err); ec.Equal(ecode.AccessKeyErr) || ec.Equal(ecode.NoLogin) {
token = &model.Token{
Mid: -1,
AccessToken: accessKey,
}
s.addCache(func() { s.d.SetOriginTokenCache(context.Background(), token) })
}
return nil, err
}
func (s *Service) currentOauth(c context.Context, accessToken string) (token *model.Token, err error) {
var t *model.Perm
if t, err = s.tokenInfo(c, accessToken); err != nil {
err = nil
}
return s.parseToken(c, t)
}
func (s *Service) otherOauth(c context.Context, accessToken string) (token *model.Token, err error) {
var t *model.Perm
if t, err = s.d.TokenFromOtherRegion(c, accessToken); err != nil {
err = nil
}
return s.parseToken(c, t)
}
func (s *Service) parseToken(c context.Context, t *model.Perm) (token *model.Token, err error) {
if t == nil {
err = ecode.AccessKeyErr
return
}
duration := time.Now().Unix() - t.Expires
if duration > _gameAdditionalExpireSeconds {
err = ecode.AccessKeyErr
return
}
if duration > 0 && duration <= _gameAdditionalExpireSeconds {
err = ecode.AccessTokenExpires
return
}
accInfo := s.Info(c, t.Mid)
token = &model.Token{
Mid: t.Mid,
AppID: t.AppID,
AccessToken: t.AccessToken,
CreateAt: t.CreateAt,
UserID: accInfo.UserID,
Uname: accInfo.Uname,
Expires: t.Expires,
Permission: "ALL",
}
return
}
// thinOauth oauth and return mid.
func (s *Service) thinOauth(c context.Context, app *model.App, accessToken string) (res *model.Info, err error) {
if accessToken == "" {
err = ecode.AccessKeyErr
return
}
region, ok := region(accessToken)
if !ok {
err = ecode.AccessKeyErr
return
}
var mid int64
if region == s.currentRegion {
mid, err = s.thinCurrentOauth(c, app.AppKey, accessToken)
if err != nil {
return
}
res = &model.Info{
Mid: mid,
}
return
}
if region == _origin {
mid, err = s.thinCurrentOauth(c, app.AppKey, accessToken)
if err == nil {
res = &model.Info{
Mid: mid,
}
return
}
}
t, err := s.d.Oauth(c, s.oauth[region], accessToken, s.currentRegion)
if err != nil {
return
}
res = &model.Info{
Mid: t.Mid,
UserID: t.UserID,
Uname: t.Uname,
}
return
}
func (s *Service) thinCurrentOauth(c context.Context, appKey, accessToken string) (res int64, err error) {
var t *model.Perm
if t, err = s.tokenInfo(c, accessToken); err != nil {
err = nil
}
if t == nil {
err = ecode.AccessKeyErr
return
}
duration := time.Now().Unix() - t.Expires
if duration > 0 && duration <= _gameAdditionalExpireSeconds {
err = ecode.AccessTokenExpires
return
}
res = t.Mid
return
}

View File

@ -0,0 +1,34 @@
package service
import (
"context"
"encoding/json"
"testing"
"go-common/library/ecode"
)
func TestService_Oauth(t *testing.T) {
once.Do(startService)
ak := "4de8aecfafc7f91cb650d6371efb1b63"
expectMid := int64(110000139)
if res, err := s.Oauth(context.TODO(), s.appMap[_gameAppKey], ak, ""); err != nil {
t.Errorf("s.Oauth() error(%v)", err)
t.FailNow()
} else if res == nil || res.Mid != expectMid {
t.Errorf("res is not correct, expected res with mid %d but got %v", expectMid, res)
t.FailNow()
} else {
str, _ := json.Marshal(res)
t.Logf("res: %s", str)
}
}
func TestService_Oauth_Expires(t *testing.T) {
once.Do(startService)
ak := "c1e220e12fd4c89a0c5449b9f8c7b062"
if _, err := s.Oauth(context.TODO(), s.appMap[_gameAppKey], ak, ""); err != ecode.AccessTokenExpires {
t.Errorf("res is not correct, expected error %v, but got %v", ecode.AccessTokenExpires, err)
t.FailNow()
}
}

View File

@ -0,0 +1,43 @@
package service
import (
"context"
"go-common/app/service/main/passport-game/model"
)
// RegV3 RegV3
func (s *Service) RegV3(c context.Context, tdoRegV3 model.TdoRegV3) (regV3 *model.ResRegV3, err error) {
regV3, err = s.d.RegV3(c, tdoRegV3)
return
}
// RegV2 RegV2
func (s *Service) RegV2(c context.Context, tdoRegV2 model.TdoRegV2) (regV2 *model.ResRegV2, err error) {
regV2, err = s.d.RegV2(c, tdoRegV2)
return
}
// Reg Reg
func (s *Service) Reg(c context.Context, tdoReg model.TdoReg) (reg *model.ResReg, err error) {
reg, err = s.d.Reg(c, tdoReg)
return
}
// ByTel ByTel
func (s *Service) ByTel(c context.Context, tdoByTel model.TdoByTel) (byTel *model.ResByTel, err error) {
byTel, err = s.d.ByTel(c, tdoByTel)
return
}
// Captcha Captcha
func (s *Service) Captcha(c context.Context, ip string) (captchaData *model.CaptchaData, err error) {
captchaData, err = s.d.Captcha(c, ip)
return
}
// SendSms SendSms
func (s *Service) SendSms(c context.Context, tdoSendSms model.TdoSendSms) (err error) {
err = s.d.SendSms(c, tdoSendSms)
return
}

View File

@ -0,0 +1 @@
package service

View File

@ -0,0 +1,65 @@
package service
import (
"context"
"time"
"go-common/app/service/main/passport-game/model"
"go-common/library/ecode"
"go-common/library/log"
)
// RenewToken renew token.
func (s *Service) RenewToken(c context.Context, accessKey, from string) (res *model.RenewToken, err error) {
if accessKey == "" {
err = ecode.AccessKeyErr
return
}
region, ok := region(accessKey)
if !ok {
err = ecode.AccessKeyErr
return
}
if region == s.currentRegion {
return s.currentRenewToken(c, accessKey)
}
if region == _origin {
if res, err = s.d.RenewToken(context.TODO(), s.renewToken[_origin], accessKey, s.currentRegion); err != nil {
return
}
if _, innerErr := s.currentRenewToken(c, accessKey); innerErr != nil {
log.Error("renewtoken succeeded on origin but failed on cloud, accessKey(%s) from(%s) error(%v)", accessKey, from, innerErr)
}
return
}
if from != "" {
s.dispatcherErrStats.Incr("dispatcher_error")
err = ErrDispatcherError
return
}
return s.d.RenewToken(c, s.renewToken[region], accessKey, s.currentRegion)
}
func (s *Service) currentRenewToken(c context.Context, accessKey string) (res *model.RenewToken, err error) {
var tokenInfo *model.Perm
if tokenInfo, err = s.tokenInfo(c, accessKey); err != nil {
return
}
if tokenInfo == nil {
err = ecode.AccessKeyErr
return
}
expires := time.Now().Unix() + _expireSeconds
token := &model.Perm{
Expires: expires,
AccessToken: accessKey,
}
if _, err = s.d.UpdateToken(c, token); err != nil {
return
}
s.d.DelTokenCache(c, accessKey)
res = &model.RenewToken{
Expires: expires,
}
return
}

View File

@ -0,0 +1,23 @@
package service
import (
"context"
"testing"
"encoding/json"
)
func TestService_RenewToken(t *testing.T) {
once.Do(startService)
ak := "4de8aecfafc7f91cb650d6371efb1b63"
if res, err := s.RenewToken(context.TODO(), ak, ""); err != nil {
t.Errorf("s.RenewToken() error(%v)", err)
t.FailNow()
} else if res == nil || res.Expires == 0 {
t.Errorf("res is not correct, expected res with expires non zero but got %v", res)
t.FailNow()
} else {
str, _ := json.Marshal(res)
t.Logf("res: %s", str)
}
}

View File

@ -0,0 +1,17 @@
package service
import (
"encoding/json"
"testing"
)
func TestServiceApp(t *testing.T) {
once.Do(startService)
if app, ok := s.appMap[_gameAppKey]; !ok {
t.Errorf("res is not correct, expect game app exists but nil")
t.FailNow()
} else {
str, _ := json.Marshal(app)
t.Logf("res: %s", str)
}
}

View File

@ -0,0 +1,35 @@
package service
import (
"context"
"strings"
"go-common/app/service/main/passport-game/model"
)
const (
_segmentation = "_"
_origin = "origin"
)
// Regions get region list.
func (s *Service) Regions(c context.Context) (res []*model.RegionInfo) {
return s.regionItems
}
// region returns region for token, use it in ok pattern:
// if token end with "_", returns "", false,
// if token end with "_foo", then returns "foo", true,
// otherwise returns "origin".
func region(token string) (string, bool) {
index := strings.Index(token, _segmentation)
if index < 0 {
return _origin, true
}
suffix := token[index+1:]
if suffix == "" {
return "", false
}
return suffix, true
}

View File

@ -0,0 +1,37 @@
package service
import (
"context"
"encoding/json"
"testing"
)
func TestService_Regions(t *testing.T) {
once.Do(startService)
m := s.Regions(context.TODO())
res, _ := json.Marshal(m)
t.Logf("res: %s", res)
}
func TestService_Region(t *testing.T) {
ak := "4de8aecfafc7f91cb650d6371efb1b63"
r, _ := region(ak)
if r != _origin {
t.FailNow()
}
t.Logf("ak: %s, region: %s", ak, r)
ak = "4de8aecfafc7f91cb650d6371efb1b63_t1"
r, _ = region(ak)
if r != "t1" {
t.FailNow()
}
t.Logf("ak: %s, region: %s", ak, r)
ak = "4de8aecfafc7f91cb650d6371efb1b63_"
_, ok := region(ak)
if ok {
t.FailNow()
}
t.Logf("ak: %s, ok: %t", ak, ok)
}

View File

@ -0,0 +1,60 @@
package service
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
)
var (
// ErrPublicKeyError public key error
ErrPublicKeyError = errors.New("public key error")
// ErrPrivateKeyError private key error
ErrPrivateKeyError = errors.New("private key error")
// ErrUnsupportedPubKey Unsupported key error
ErrUnsupportedPubKey = errors.New("unsupported public key")
// ErrUnsupportedPrivKey Private key error
ErrUnsupportedPrivKey = errors.New("unsupported private key")
)
func pubKey(publicKey []byte) (*rsa.PublicKey, error) {
block, _ := pem.Decode(publicKey)
if block == nil {
return nil, ErrPublicKeyError
}
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, err
}
pub, ok := pubInterface.(*rsa.PublicKey)
if !ok {
return nil, ErrUnsupportedPubKey
}
return pub, nil
}
func privKey(privateKey []byte) (*rsa.PrivateKey, error) {
block, _ := pem.Decode(privateKey)
if block == nil {
return nil, ErrPrivateKeyError
}
privInterface, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
priv, ok := privInterface.(*rsa.PrivateKey)
if !ok {
return nil, ErrUnsupportedPrivKey
}
return priv, nil
}
func rsaEncryptPKCS8(pub *rsa.PublicKey, origData []byte) ([]byte, error) {
return rsa.EncryptPKCS1v15(rand.Reader, pub, origData)
}
func rsaDecryptPKCS8(priv *rsa.PrivateKey, ciphertext []byte) ([]byte, error) {
return rsa.DecryptPKCS1v15(rand.Reader, priv, ciphertext)
}

View File

@ -0,0 +1,65 @@
package service
import (
"bufio"
"encoding/base64"
"fmt"
"io"
"os"
"testing"
)
func TestDecode(t *testing.T) {
s := "Qiu+Iyqi/URq8fbd/FQAtN8CPJ/LT9AAG5/dSd+RSRjH4OgGp3tJMvOk7uqzzgWDi0EYDsLp2xme61NdjhITz1eRmN11oyu2cYqsk9Rqp0o3LzNHeMuUL4GMdWlhRNBQMoNJdzmSaPZoIlgL3vxK+ghg/zF8clqvMSYryuy+rZI="
key, err := privKey([]byte(_originPrivKey))
fmt.Println(err)
d, _ := base64.StdEncoding.DecodeString(s)
b, err := rsaDecryptPKCS8(key, d)
fmt.Println(err)
fmt.Println(string(b))
}
func TestRSADecryptPKCS8(t *testing.T) {
plain := []byte("hello")
pub, err := pubKey([]byte(_originPubKey))
if err != nil {
t.Errorf("failed to init pub key, error(%v)", err)
t.FailNow()
}
d, err := rsaEncryptPKCS8(pub, plain)
if err != nil {
t.Errorf("failed to rsa encrypt, error(%v)", err)
t.FailNow()
}
t.Logf("d: %s", base64.StdEncoding.EncodeToString(d))
priv, err := privKey([]byte(_originPrivKey))
if err != nil {
t.Errorf("failed to init priv key, error(%v)", err)
t.FailNow()
}
fn := "/tmp/pwd.txt"
f, err := os.Open(fn)
if err != nil {
t.Errorf("failed to open file %s, error(%v)", fn, err)
t.FailNow()
}
defer f.Close()
rd := bufio.NewReader(f)
i := 0
for {
line, err := rd.ReadString('\n')
if err != nil || io.EOF == err {
break
}
d, _ = base64.StdEncoding.DecodeString(line)
p, err := rsaDecryptPKCS8(priv, d)
if err != nil {
t.Errorf("failed to rsa decrypt, error(%v)", err)
t.FailNow()
}
i++
t.Logf("%d: %s\n", i, p[16:])
}
}

View File

@ -0,0 +1,118 @@
package service
import (
"fmt"
"math/rand"
"strconv"
"time"
)
const (
_bits = uint64(4)
_splitOn = 32 / _bits
)
var (
table = []uint64{
0x4f3a97cb, 0x8ae2d379, 0xe8df369a, 0x5ac82647, 0xcdaf6987, 0xabd28536, 0x3e5f2a7b, 0x792e85df,
0xeac3d972, 0xca9b7fe5, 0xbdcf5473, 0x895ad732, 0xc9d6b324, 0xd3549a72, 0xde72ab89, 0xf4a6dc53,
0x6a8e752b, 0xa736d25f, 0xc3ad8296, 0xb435f689, 0x7fce594b, 0x529ca743, 0x3c4ab2d7, 0x94c8adf6,
0x893746c2, 0x6ceda579, 0xcad36b75, 0x6f4a973e, 0xf3a49c56, 0xb645f2d9, 0xd72a56f8, 0x4b3d6fa9,
0xd354cf2a, 0x26b4f5d8, 0x3e9f64ad, 0xae4fd326, 0x3f9247d6, 0xe4c67f95, 0xfed8c9b4, 0x249637db,
0xdefabc54, 0xa9ebd87c, 0xcf2864ea, 0xf632d475, 0x5e3b6897, 0xed7f94b8, 0x67a4cfd2, 0x97a82e65,
0x2369b7a4, 0x2ca3e6d4, 0xc57fba36, 0xdf3e7846, 0xde324ba5, 0x7ec56f24, 0xb598c3af, 0x389fd4ae,
0xa3b6472c, 0x2f94a8be, 0x93fcab42, 0x82f34aeb, 0x94e8b372, 0x87c42b9e, 0x2f9b574c, 0x7ec693fa,
0x9245fc67, 0x823bf4ce, 0x9357f84d, 0xed529a87, 0xb4625ead, 0xbcd4f6a9, 0x7863ca52, 0xd4762cef,
0xe8d6c479, 0xbc46f579, 0xa9486fdc, 0xced6f289, 0xd8a3b629, 0x49fce523, 0x62e8db97, 0xc23bf769,
0xa9c64d7f, 0x52dab6f7, 0x965cdf8e, 0xc4872fe9, 0x9764de53, 0x24bef897, 0x5b7a962c, 0x3f8d72be,
0xd26fa89c, 0x58bf742e, 0xac3bd967, 0x36cae942, 0x48d3fb9c, 0xa2f59ed3, 0xa6f8379d, 0x29bf46d7,
0x8cdbe243, 0x375c4bf9, 0x872f9dc5, 0x87a46ef5, 0x53d48ac9, 0x97e6ca3d, 0x2fec5a3b, 0x597dafe3,
0x382ed7a9, 0xbc34d687, 0x869ecbf7, 0x7b38549a, 0x9f28746c, 0x95cb7e83, 0xec85f9a7, 0x2a947c8e,
0x7ba689fd, 0xebc24893, 0xa362cf7e, 0xa48e3cb5, 0xe247589d, 0x7c92edaf, 0x84635c2d, 0xad2c6bfe,
0xec456daf, 0x2d6e5f47, 0xfa9ce625, 0x7c4a8b62, 0x9cd728f5, 0x3be4a29d, 0xd62a589c, 0x843cb629,
0x4ce5b6d3, 0x2fd6a9ce, 0x8d7af3bc, 0x8f37a695, 0xfe935da4, 0x4d8b6ea2, 0xa52dc4e9, 0x8e2a537b,
0x7e23456f, 0x6cb8dafe, 0x957bf34d, 0x4ec72ad8, 0xa75c4982, 0x83afb76e, 0xb895fca6, 0x865abd24,
0x9ae2475d, 0xf3c45eb8, 0xba4d2ef5, 0xb2da463e, 0xfd392a5e, 0x76a9fd58, 0x3ead48f6, 0x8ea62537,
0xd6c35ba2, 0x758d9e24, 0xd524ec93, 0x67bc42a5, 0x354d9f87, 0xe2d3578f, 0xe87452fa, 0x5e439fca,
0xd29b37c8, 0x8fe64c3b, 0x4ac5368d, 0x5e8acf9b, 0x6f9c3ad2, 0xaef3827b, 0x5328e46b, 0xbdef7ca9,
0x3da592c4, 0x45fe7db2, 0xc9b65a3d, 0x4a578ec3, 0xc46deab9, 0xb3689edc, 0x84aed59f, 0x235b9af7,
0xa9b6d48f, 0x6de379bf, 0x2749fa5e, 0x2469a7ef, 0xdf9e62a7, 0xb39a86d2, 0x8539b72c, 0x8dfa9ebc,
0xdec397f5, 0xdba3c4e2, 0x9a38e6fd, 0xe98a734f, 0xe94b8d7f, 0x874cd9b3, 0xb75c6ef4, 0x9f56378c,
0xc43f2d78, 0x74ea9253, 0x2c5dbef4, 0xbc7e26f9, 0x943b2c6d, 0x25faeb76, 0x53b278de, 0x6eb5948f,
0xc4967358, 0x49f63a7e, 0x7a596ec4, 0x948cabf5, 0x945c638e, 0x6fd258b7, 0x697e8b3f, 0x56ab7823,
0xc53b6a89, 0xa3bfc579, 0xaec45d36, 0xcdea9b28, 0x9e8f2356, 0xdb694a2e, 0xdf732e8a, 0xec7463d5,
0xbf5ec9a8, 0x6dbfa984, 0xc4798e5a, 0x67e9382b, 0xe7ac3249, 0x5e238b9a, 0xbd632eaf, 0xaf92b685,
0x6bcae435, 0x97236fd8, 0x37fcbea4, 0x5fe9da23, 0xb593a4f7, 0x3e27d84c, 0xa5db932f, 0x8c6274de,
0xca54bd72, 0x63f42ed5, 0x6ad37285, 0xbd4fe7c9, 0x5f49a6b3, 0x38b592ec, 0x273d456b, 0x4e9253b7,
0xf2da9b8c, 0xb85c642d, 0x3d7489ca, 0x7426fe3b, 0x4bce6ad2, 0x3276becd, 0x96f43bec, 0xf296dba4,
0x3ebc8d72, 0xf593b4ca, 0x2a63547f, 0xa5bcd87e, 0x39fd25ae, 0xce6f4b38, 0xf36cd978, 0x62e94a37,
}
)
// TsSeconds2Hash generate hash from seconds ts.
func TsSeconds2Hash(tsSecond int64) string {
hashSeedMills := time.Now().UnixNano() / time.Millisecond.Nanoseconds()
randomIndex := rand.Intn(255)
hashVal := md5Hex(strconv.FormatInt(hashSeedMills, 10))
hashVal = hashVal[:16]
ris := fmt.Sprintf("%02x", randomIndex)
hashVal = replaceStr(hashVal, ris, 0)
val := table[randomIndex]
ts := fmt.Sprintf("%08x", tsSecond)
poses := decompress(val)
for i, pos := range poses {
s := ts[i : i+1]
hashVal = replaceStr(hashVal, s, int(pos))
}
return hashVal
}
func replaceStr(origin, s string, pos int) string {
if pos > 0 {
return origin[:pos] + s + origin[pos+len(s):]
}
return s + origin[pos+len(s):]
}
func decompress(mixed uint64) []uint64 {
filterVal := uint64((1 << _bits) - 1)
val := make([]uint64, _splitOn)
itemNums := _splitOn
mixedArr := []uint64{mixed}
n := uint64(0)
for _, sval := range mixedArr {
for k := uint64(0); k < _splitOn; k++ {
var dval uint64
if k == 0 {
dval = sval & filterVal
} else {
dval = (sval >> (_bits * k)) & filterVal
}
val[k] = dval
n++
if n == itemNums {
break
}
}
if n == itemNums {
break
}
}
return val
}
// Hash2TsSeconds parse ts seconds from hash.
func Hash2TsSeconds(timeHash string) (ts int64, err error) {
randomIndex, err := strconv.ParseInt(timeHash[0:2], 16, 64)
if err != nil {
return
}
val := table[randomIndex]
poses := decompress(val)
tsStr := ""
for _, pos := range poses {
tsStr = tsStr + timeHash[pos:pos+1]
}
ts, err = strconv.ParseInt(tsStr, 16, 64)
return
}

View File

@ -0,0 +1,38 @@
package service
import (
"math/rand"
"testing"
"time"
)
func BenchmarkTsSecond2Hash(b *testing.B) {
ts := time.Now().Unix()
for i := 0; i < b.N; i++ {
ts += int64(rand.Intn(100))
hash := TsSeconds2Hash(ts)
if ats, err := Hash2TsSeconds(hash); err != nil {
b.Errorf("failed to parse hash, error(%v)", err)
b.FailNow()
} else if ats != ts {
b.Errorf("hash: %s, expect %d but got %d", hash, ts, ats)
b.FailNow()
}
}
}
func TestDecompress(t *testing.T) {
val := table[5] // 0xabd28536
exp := []uint64{6, 3, 5, 8, 2, 13, 11, 10}
poses := decompress(val)
if len(poses) != len(exp) {
t.Errorf("res is not correct, expected poses length equal to exp length, but not, poses length: %d, exp length: %d", len(poses), len(exp))
t.FailNow()
}
for i, item := range exp {
if poses[i] != item {
t.Errorf("failed to decompress, expected %v but got %v", exp, poses)
t.FailNow()
}
}
}

View File

@ -0,0 +1,124 @@
package service
import (
"context"
"crypto/rsa"
"go-common/app/service/main/passport-game/conf"
"go-common/app/service/main/passport-game/dao"
"go-common/app/service/main/passport-game/model"
"go-common/library/log"
"go-common/library/stat"
"go-common/library/stat/prom"
)
// Service service.
type Service struct {
c *conf.Config
d *dao.Dao
missch chan func()
appMap map[string]*model.App
originPubKey *rsa.PublicKey
cloudRSAKey *RSAKey
proxy bool
currentRegion string
oauth map[string]string
renewToken map[string]string
regionItems []*model.RegionInfo
dispatcherErrStats stat.Stat
}
// RSAKey RSA public and private key.
type RSAKey struct {
pub *rsa.PublicKey
priv *rsa.PrivateKey
}
// New new a service instance.
func New(c *conf.Config) (s *Service) {
d := dao.New(c)
// load apps
apps, err := d.Apps(context.TODO())
if err != nil {
panic(err)
}
if len(apps) == 0 {
panic("apps loaded from db is empty, abort")
}
appMap := make(map[string]*model.App, len(apps))
for _, app := range apps {
appMap[app.AppKey] = app
}
// load origin public key
key, err := d.RSAKeyOrigin(context.TODO())
if err != nil {
panic(err)
}
originPub, err := pubKey([]byte(key.Key))
if err != nil {
panic(err)
}
// load origin public and private key for cloud
pub, err := pubKey([]byte(_originPubKey))
if err != nil {
panic(err)
}
priv, err := privKey([]byte(_originPrivKey))
if err != nil {
panic(err)
}
// init
s = &Service{
c: c,
d: d,
missch: make(chan func(), 10240),
appMap: appMap,
originPubKey: originPub,
cloudRSAKey: &RSAKey{
pub: pub,
priv: priv,
},
proxy: c.Proxy,
currentRegion: c.Dispatcher.Name,
oauth: c.Dispatcher.Oauth,
renewToken: c.Dispatcher.RenewToken,
regionItems: c.Dispatcher.RegionInfos,
dispatcherErrStats: prom.BusinessErrCount,
}
go s.cacheproc()
return
}
// APP query appkey
func (s *Service) APP(app string) (v *model.App, ok bool) {
v, ok = s.appMap[app]
return
}
func (s *Service) addCache(f func()) {
select {
case s.missch <- f:
default:
log.Warn("cache chan full")
}
}
// cacheproc is a routine for executing closure.
func (s *Service) cacheproc() {
for {
f := <-s.missch
f()
}
}
// Ping check server ok.
func (s *Service) Ping(c context.Context) (err error) {
err = s.d.Ping(c)
return
}
// Close close service, including closing dao.
func (s *Service) Close() (err error) {
s.d.Close()
return
}

View File

@ -0,0 +1,31 @@
package service
import (
"fmt"
"sync"
"testing"
"go-common/app/service/main/passport-game/conf"
)
var (
once sync.Once
s *Service
)
func startService() {
if err := conf.Init(); err != nil {
panic(fmt.Sprintf("conf.Init() error(%v)", err))
}
s = New(conf.Conf)
}
func TestNew(t *testing.T) {
once.Do(startService)
if s.c.AccountURI == "" || s.c.PassportURI == "" {
t.Errorf("conf is not correct, expected account URI and passport URI not empty but not, account URI: %s, passport URI: %s", s.c.AccountURI, s.c.PassportURI)
t.FailNow()
} else {
t.Logf("s.c.AccountURI: %s, s.c.PassportURI: %s", s.c.AccountURI, s.c.PassportURI)
}
}