diff --git a/internal/db/user.go b/internal/db/user.go index 58a1e81..06d2f76 100644 --- a/internal/db/user.go +++ b/internal/db/user.go @@ -19,7 +19,7 @@ func WithRole(role model.Role) CreateUserConfig { } } -func CreateUser(username string, p provider.OAuth2Provider, puid uint, conf ...CreateUserConfig) (*model.User, error) { +func CreateUser(username string, p provider.OAuth2Provider, puid uint64, conf ...CreateUserConfig) (*model.User, error) { u := &model.User{ Username: username, Role: model.RoleUser, @@ -41,7 +41,7 @@ func CreateUser(username string, p provider.OAuth2Provider, puid uint, conf ...C } // 只有当provider和puid没有找到对应的user时才会创建 -func CreateOrLoadUser(username string, p provider.OAuth2Provider, puid uint, conf ...CreateUserConfig) (*model.User, error) { +func CreateOrLoadUser(username string, p provider.OAuth2Provider, puid uint64, conf ...CreateUserConfig) (*model.User, error) { var user model.User var userProvider model.UserProvider @@ -60,7 +60,7 @@ func CreateOrLoadUser(username string, p provider.OAuth2Provider, puid uint, con return &user, nil } -func GetProviderUserID(p provider.OAuth2Provider, puid uint) (string, error) { +func GetProviderUserID(p provider.OAuth2Provider, puid uint64) (string, error) { var userProvider model.UserProvider if err := db.Where("provider = ? AND provider_user_id = ?", p, puid).First(&userProvider).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { diff --git a/internal/model/oauth2.go b/internal/model/oauth2.go index 005ca33..a172953 100644 --- a/internal/model/oauth2.go +++ b/internal/model/oauth2.go @@ -8,7 +8,7 @@ import ( type UserProvider struct { Provider provider.OAuth2Provider `gorm:"not null;primarykey"` - ProviderUserID uint `gorm:"not null;primarykey;autoIncrement:false"` + ProviderUserID uint64 `gorm:"not null;primarykey;autoIncrement:false"` CreatedAt time.Time UpdatedAt time.Time UserID string `gorm:"not null;index"` diff --git a/internal/op/users.go b/internal/op/users.go index 1fbb0d3..555088b 100644 --- a/internal/op/users.go +++ b/internal/op/users.go @@ -43,7 +43,7 @@ func GetUserById(id string) (*User, error) { return u2, userCache.SetWithExpire(id, u2, time.Hour) } -func CreateUser(username string, p provider.OAuth2Provider, pid uint, conf ...db.CreateUserConfig) (*User, error) { +func CreateUser(username string, p provider.OAuth2Provider, pid uint64, conf ...db.CreateUserConfig) (*User, error) { if username == "" { return nil, errors.New("username cannot be empty") } @@ -59,7 +59,7 @@ func CreateUser(username string, p provider.OAuth2Provider, pid uint, conf ...db return u2, userCache.SetWithExpire(u.ID, u2, time.Hour) } -func CreateOrLoadUser(username string, p provider.OAuth2Provider, pid uint, conf ...db.CreateUserConfig) (*User, error) { +func CreateOrLoadUser(username string, p provider.OAuth2Provider, pid uint64, conf ...db.CreateUserConfig) (*User, error) { if username == "" { return nil, errors.New("username cannot be empty") } @@ -75,7 +75,7 @@ func CreateOrLoadUser(username string, p provider.OAuth2Provider, pid uint, conf return u2, userCache.SetWithExpire(u.ID, u2, time.Hour) } -func GetUserByProvider(p provider.OAuth2Provider, pid uint) (*User, error) { +func GetUserByProvider(p provider.OAuth2Provider, pid uint64) (*User, error) { uid, err := db.GetProviderUserID(p, pid) if err != nil { return nil, err diff --git a/internal/provider/plugins/client.go b/internal/provider/plugins/client.go index c009da4..4271d09 100644 --- a/internal/provider/plugins/client.go +++ b/internal/provider/plugins/client.go @@ -79,6 +79,6 @@ func (c *GRPCClient) GetUserInfo(ctx context.Context, tk *oauth2.Token) (*provid } return &provider.UserInfo{ Username: resp.Username, - ProviderUserID: uint(resp.ProviderUserId), + ProviderUserID: resp.ProviderUserId, }, nil } diff --git a/internal/provider/plugins/example/example_gitee.go b/internal/provider/plugins/example/example_gitee.go index 2c0b654..de12319 100644 --- a/internal/provider/plugins/example/example_gitee.go +++ b/internal/provider/plugins/example/example_gitee.go @@ -80,7 +80,7 @@ func (p *GiteeProvider) GetUserInfo(ctx context.Context, tk *oauth2.Token) (*pro } type giteeUserInfo struct { - ID uint `json:"id"` + ID uint64 `json:"id"` Login string `json:"login"` } diff --git a/internal/provider/provider.go b/internal/provider/provider.go index d6d4e35..3b3e3d4 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -10,7 +10,7 @@ type OAuth2Provider string type UserInfo struct { Username string - ProviderUserID uint + ProviderUserID uint64 } type Oauth2Option struct { diff --git a/internal/provider/providers/baidu-netdisk.go b/internal/provider/providers/baidu-netdisk.go index 76f8584..6a2dcbf 100644 --- a/internal/provider/providers/baidu-netdisk.go +++ b/internal/provider/providers/baidu-netdisk.go @@ -71,7 +71,7 @@ type baiduNetDiskProviderUserInfo struct { BaiduName string `json:"baidu_name"` Errmsg string `json:"errmsg"` Errno int `json:"errno"` - Uk uint `json:"uk"` + Uk uint64 `json:"uk"` } func init() { diff --git a/internal/provider/providers/baidu.go b/internal/provider/providers/baidu.go index d60e6ef..be4ada0 100644 --- a/internal/provider/providers/baidu.go +++ b/internal/provider/providers/baidu.go @@ -3,12 +3,11 @@ package providers import ( "context" "fmt" - "hash/crc32" + "hash/crc64" "net/http" json "github.com/json-iterator/go" "github.com/synctv-org/synctv/internal/provider" - "github.com/zijiren233/stream" "golang.org/x/oauth2" ) @@ -62,7 +61,7 @@ func (p *BaiduProvider) GetUserInfo(ctx context.Context, tk *oauth2.Token) (*pro } return &provider.UserInfo{ Username: ui.Uname, - ProviderUserID: uint(crc32.ChecksumIEEE(stream.StringToBytes(ui.Openid))), + ProviderUserID: crc64.Checksum([]byte(ui.Openid), crc64.MakeTable(crc64.ECMA)), }, nil } diff --git a/internal/provider/providers/gitee.go b/internal/provider/providers/gitee.go index 748951f..46e6235 100644 --- a/internal/provider/providers/gitee.go +++ b/internal/provider/providers/gitee.go @@ -63,7 +63,7 @@ func (p *GiteeProvider) GetUserInfo(ctx context.Context, tk *oauth2.Token) (*pro } type giteeUserInfo struct { - ID uint `json:"id"` + ID uint64 `json:"id"` Login string `json:"login"` } diff --git a/internal/provider/providers/github.go b/internal/provider/providers/github.go index 7907b25..7c21869 100644 --- a/internal/provider/providers/github.go +++ b/internal/provider/providers/github.go @@ -62,7 +62,7 @@ func (p *GithubProvider) GetUserInfo(ctx context.Context, tk *oauth2.Token) (*pr type githubUserInfo struct { Login string `json:"login"` - ID uint `json:"id"` + ID uint64 `json:"id"` } func init() { diff --git a/internal/provider/providers/google.go b/internal/provider/providers/google.go index b6c378f..0c388df 100644 --- a/internal/provider/providers/google.go +++ b/internal/provider/providers/google.go @@ -65,6 +65,6 @@ func init() { } type googleUserInfo struct { - ID uint `json:"id,string"` + ID uint64 `json:"id,string"` Name string `json:"name"` } diff --git a/internal/provider/providers/microsoft.go b/internal/provider/providers/microsoft.go index e2adb7a..17fd608 100644 --- a/internal/provider/providers/microsoft.go +++ b/internal/provider/providers/microsoft.go @@ -2,7 +2,7 @@ package providers import ( "context" - "hash/crc32" + "hash/crc64" "net/http" json "github.com/json-iterator/go" @@ -58,7 +58,7 @@ func (p *MicrosoftProvider) GetUserInfo(ctx context.Context, tk *oauth2.Token) ( } return &provider.UserInfo{ Username: ui.DisplayName, - ProviderUserID: uint(crc32.ChecksumIEEE(stream.StringToBytes(ui.ID))), + ProviderUserID: crc64.Checksum(stream.StringToBytes(ui.ID), crc64.MakeTable(crc64.ECMA)), }, nil } diff --git a/internal/provider/providers/qq.go b/internal/provider/providers/qq.go new file mode 100644 index 0000000..891f666 --- /dev/null +++ b/internal/provider/providers/qq.go @@ -0,0 +1,74 @@ +package providers + +import ( + "context" + "fmt" + "net/http" + "strconv" + + json "github.com/json-iterator/go" + "github.com/synctv-org/synctv/internal/provider" + "golang.org/x/oauth2" +) + +type QQProvider struct { + config oauth2.Config +} + +func (p *QQProvider) Init(c provider.Oauth2Option) { + p.config.Scopes = []string{"get_user_info"} + p.config.Endpoint = oauth2.Endpoint{ + AuthURL: "https://graph.qq.com/oauth2.0/authorize", + TokenURL: "https://graph.qq.com/oauth2.0/token?grant_type=authorization_code", + } + p.config.ClientID = c.ClientID + p.config.ClientSecret = c.ClientSecret + p.config.RedirectURL = c.RedirectURL +} + +func (p *QQProvider) Provider() provider.OAuth2Provider { + return "qq" +} + +func (p *QQProvider) NewAuthURL(state string) string { + return p.config.AuthCodeURL(state, oauth2.AccessTypeOnline) +} + +func (p *QQProvider) GetToken(ctx context.Context, code string) (*oauth2.Token, error) { + return p.config.Exchange(ctx, code) +} + +func (p *QQProvider) RefreshToken(ctx context.Context, tk string) (*oauth2.Token, error) { + return p.config.TokenSource(ctx, &oauth2.Token{RefreshToken: tk}).Token() +} + +func (p *QQProvider) GetUserInfo(ctx context.Context, tk *oauth2.Token) (*provider.UserInfo, error) { + client := p.config.Client(ctx, tk) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("https://graph.qq.com/oauth2.0/me?access_token=%s&fmt=json", tk.AccessToken), nil) + if err != nil { + return nil, err + } + resp, err := client.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + ui := qqProviderUserInfo{} + err = json.NewDecoder(resp.Body).Decode(&ui) + if err != nil { + return nil, err + } + return &provider.UserInfo{ + Username: strconv.FormatUint(ui.Openid, 10), + ProviderUserID: ui.Openid, + }, nil +} + +func init() { + RegisterProvider(new(QQProvider)) +} + +type qqProviderUserInfo struct { + ClientID string `json:"client_id"` + Openid uint64 `json:"openid,string"` +}