111 lines
3.4 KiB
Go
111 lines
3.4 KiB
Go
package oauth2
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"net/http"
|
|
|
|
"github.com/mayswind/ezbookkeeping/pkg/core"
|
|
"github.com/mayswind/ezbookkeeping/pkg/errs"
|
|
"github.com/mayswind/ezbookkeeping/pkg/log"
|
|
)
|
|
|
|
type nextcloudUserInfoResponse struct {
|
|
OCS *struct {
|
|
Meta *struct {
|
|
Status string `json:"status"`
|
|
StatusCode int `json:"statuscode"`
|
|
} `json:"meta"`
|
|
Data *struct {
|
|
ID string `json:"id"`
|
|
Email string `json:"email"`
|
|
DisplayName string `json:"display-name"`
|
|
} `json:"data"`
|
|
} `json:"ocs"`
|
|
}
|
|
|
|
// NextcloudOAuth2Provider represents Nextcloud OAuth 2.0 provider
|
|
type NextcloudOAuth2Provider struct {
|
|
baseUrl string
|
|
}
|
|
|
|
// NewNextcloudOAuth2Provider creates a new Nextcloud OAuth 2.0 provider instance
|
|
func NewNextcloudOAuth2Provider(baseUrl string) OAuth2Provider {
|
|
if baseUrl[len(baseUrl)-1] != '/' {
|
|
baseUrl += "/"
|
|
}
|
|
|
|
return &NextcloudOAuth2Provider{
|
|
baseUrl: baseUrl,
|
|
}
|
|
}
|
|
|
|
// GetAuthUrl returns the authentication url of the Nextcloud provider
|
|
func (p *NextcloudOAuth2Provider) GetAuthUrl() string {
|
|
return p.baseUrl + "apps/oauth2/authorize"
|
|
}
|
|
|
|
// GetTokenUrl returns the token url of the Nextcloud provider
|
|
func (p *NextcloudOAuth2Provider) GetTokenUrl() string {
|
|
return p.baseUrl + "apps/oauth2/api/v1/token"
|
|
}
|
|
|
|
// GetUserInfo returns the user info by the Nextcloud provider
|
|
func (p *NextcloudOAuth2Provider) GetUserInfo(c core.Context, oauth2Client *http.Client) (*OAuth2UserInfo, error) {
|
|
url := p.baseUrl + "ocs/v2.php/cloud/user?format=json"
|
|
resp, err := oauth2Client.Get(url)
|
|
|
|
if err != nil {
|
|
log.Errorf(c, "[nextcloud_oauth2_provider.GetUserInfo] failed to get user info response, because %s", err.Error())
|
|
return nil, errs.ErrFailedToRequestRemoteApi
|
|
}
|
|
|
|
defer resp.Body.Close()
|
|
body, err := io.ReadAll(resp.Body)
|
|
|
|
log.Debugf(c, "[nextcloud_oauth2_provider.GetUserInfo] response is %s", body)
|
|
|
|
if resp.StatusCode != 200 {
|
|
log.Errorf(c, "[nextcloud_oauth2_provider.GetUserInfo] failed to get user info response, because response code is %d", resp.StatusCode)
|
|
return nil, errs.ErrFailedToRequestRemoteApi
|
|
}
|
|
|
|
return p.parseUserInfo(c, body)
|
|
}
|
|
|
|
// GetScopes returns the scopes required by the Nextcloud provider
|
|
func (p *NextcloudOAuth2Provider) GetScopes() []string {
|
|
return []string{"profile", "email"}
|
|
}
|
|
|
|
func (p *NextcloudOAuth2Provider) parseUserInfo(c core.Context, body []byte) (*OAuth2UserInfo, error) {
|
|
userInfoResp := &nextcloudUserInfoResponse{}
|
|
err := json.Unmarshal(body, &userInfoResp)
|
|
|
|
if err != nil {
|
|
log.Warnf(c, "[nextcloud_oauth2_provider.parseUserInfo] failed to parse user info response body, because %s", err.Error())
|
|
return nil, errs.ErrCannotRetrieveUserInfo
|
|
}
|
|
|
|
if userInfoResp.OCS == nil || userInfoResp.OCS.Meta == nil || userInfoResp.OCS.Data == nil {
|
|
log.Warnf(c, "[nextcloud_oauth2_provider.parseUserInfo] invalid user info response body")
|
|
return nil, errs.ErrCannotRetrieveUserInfo
|
|
}
|
|
|
|
if userInfoResp.OCS.Meta.StatusCode != 200 {
|
|
log.Warnf(c, "[nextcloud_oauth2_provider.parseUserInfo] user info response status code is %d", userInfoResp.OCS.Meta.StatusCode)
|
|
return nil, errs.ErrCannotRetrieveUserInfo
|
|
}
|
|
|
|
if userInfoResp.OCS.Data.ID == "" {
|
|
log.Warnf(c, "[nextcloud_oauth2_provider.parseUserInfo] user info id is empty")
|
|
return nil, errs.ErrCannotRetrieveUserInfo
|
|
}
|
|
|
|
return &OAuth2UserInfo{
|
|
UserName: userInfoResp.OCS.Data.ID,
|
|
Email: userInfoResp.OCS.Data.Email,
|
|
NickName: userInfoResp.OCS.Data.DisplayName,
|
|
}, nil
|
|
}
|