Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Control faucetPackage generation by OAuth Account #12

Merged
merged 2 commits into from
Dec 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 32 additions & 7 deletions handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,15 @@ func (f *faucet) authOpenHandler(_ *apirest.APIdata, ctx *httprouter.HTTPContext
if err != nil {
return err
}
if funded, t := f.storage.checkIsFundedAddress(addr, "open"); funded {
if funded, t := f.storage.checkIsFundedUserID(addr.Bytes(), "open"); funded {
errReason := fmt.Sprintf("address %s already funded, wait until %s", addr.Hex(), t)
return ctx.Send(new(HandlerResponse).SetError(errReason).MustMarshall(), CodeErrFlood)
}
data, err := f.prepareFaucetPackage(addr, "open")
if err != nil {
return err
}
if err := f.storage.addFundedAddress(addr, "open"); err != nil {
if err := f.storage.addFundedUserID(addr.Bytes(), "open"); err != nil {
return err
}
return ctx.Send(new(HandlerResponse).Set(data).MustMarshall(), apirest.HTTPstatusOK)
Expand Down Expand Up @@ -123,7 +123,7 @@ func (f *faucet) authOAuthHandler(msg *apirest.APIdata, ctx *httprouter.HTTPCont
if err != nil {
return err
}
if funded, t := f.storage.checkIsFundedAddress(addr, "oauth"); funded {
if funded, t := f.storage.checkIsFundedUserID(addr.Bytes(), "oauth"); funded {
errReason := fmt.Sprintf("address %s already funded, wait until %s", addr.Hex(), t)
return ctx.Send(new(HandlerResponse).SetError(errReason).MustMarshall(), CodeErrFlood)
}
Expand All @@ -139,16 +139,41 @@ func (f *faucet) authOAuthHandler(msg *apirest.APIdata, ctx *httprouter.HTTPCont
return ctx.Send(new(HandlerResponse).SetError(ReasonErrOauthProviderNotFound).MustMarshall(), CodeErrOauthProviderNotFound)
}

_, err = provider.GetOAuthToken(newRequest.Code, newRequest.RedirectURL)
token, err := provider.GetOAuthToken(newRequest.Code, newRequest.RedirectURL)
if err != nil {
return ctx.Send(new(HandlerResponse).SetError(ReasonErrOauthProviderError).MustMarshall(), CodeErrOauthProviderError)
}

profileRaw, err := provider.GetOAuthProfile(token)
if err != nil {
log.Warnw("error obtaining the profile", "err", err)
return ctx.Send(new(HandlerResponse).SetError(ReasonErrOauthProviderError).MustMarshall(), CodeErrOauthProviderError)
}

var profile map[string]interface{}
if err := json.Unmarshal(profileRaw, &profile); err != nil {
log.Warnw("error marshalling the profile", "err", err)
return ctx.Send(new(HandlerResponse).SetError(ReasonErrOauthProviderError).MustMarshall(), CodeErrOauthProviderError)
}

// Check if the oauth profile is already funded
fundedProfileField := profile[provider.UsernameField].(string)
fundedAuthType := "oauth_" + newRequest.Provider
if funded, t := f.storage.checkIsFundedUserID([]byte(fundedProfileField), fundedAuthType); funded {
errReason := fmt.Sprintf("user %s already funded, wait until %s", fundedProfileField, t)
return ctx.Send(new(HandlerResponse).SetError(errReason).MustMarshall(), CodeErrFlood)
}

data, err := f.prepareFaucetPackage(addr, "oauth")
if err != nil {
return err
}
if err := f.storage.addFundedAddress(addr, "oauth"); err != nil {

// Add address and profile to the funded list
if err := f.storage.addFundedUserID(addr.Bytes(), "oauth"); err != nil {
return err
}
if err := f.storage.addFundedUserID([]byte(fundedProfileField), fundedAuthType); err != nil {
return err
}

Expand Down Expand Up @@ -209,7 +234,7 @@ func (f *faucet) authAragonDaoHandler(msg *apirest.APIdata, ctx *httprouter.HTTP
}

// Check if the address is already funded
if funded, t := f.storage.checkIsFundedAddress(addr, "aragon"); funded {
if funded, t := f.storage.checkIsFundedUserID(addr.Bytes(), "aragon"); funded {
errReason := fmt.Sprintf("address %s already funded, wait until %s", addr.Hex(), t)
return ctx.Send(new(HandlerResponse).SetError(errReason).MustMarshall(), CodeErrFlood)
}
Expand Down Expand Up @@ -237,7 +262,7 @@ func (f *faucet) authAragonDaoHandler(msg *apirest.APIdata, ctx *httprouter.HTTP
return ctx.Send(new(HandlerResponse).SetError(err.Error()).MustMarshall(), CodeErrInternalError)
}

if err := f.storage.addFundedAddress(addr, "aragon"); err != nil {
if err := f.storage.addFundedUserID(addr.Bytes(), "aragon"); err != nil {
return ctx.Send(new(HandlerResponse).SetError(err.Error()).MustMarshall(), CodeErrInternalError)
}

Expand Down
5 changes: 4 additions & 1 deletion oauthhandler/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ providers:
client_id: FACEBOOK_CLIENT_ID
client_secret: FACEBOOK_CLIENT_SECRET
scope: email
username_field: email
github:
name: Github
auth_url: https://github.com/login/oauth/authorize
Expand All @@ -15,6 +16,7 @@ providers:
client_id: GITHUB_CLIENT_ID
client_secret: GITHUB_CLIENT_SECRET
scope: user:email
username_field: login
twitter:
name: Twitter
auth_url: https://api.twitter.com/oauth/authenticate
Expand Down Expand Up @@ -46,4 +48,5 @@ providers:
profile_url: https://www.googleapis.com/oauth2/v1/userinfo
client_id: GOOGLE_CLIENT_ID
client_secret: GOOGLE_CLIENT_SECRET
scope: email
scope: email
username_field: id
48 changes: 26 additions & 22 deletions oauthhandler/providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,26 @@ type Config struct {

// ProviderConfig represents the configuration for an OAuth provider.
type ProviderConfig struct {
Name string `yaml:"name"`
AuthURL string `yaml:"auth_url"`
TokenURL string `yaml:"token_url"`
ProfileURL string `yaml:"profile_url"`
ClientID string `yaml:"client_id"`
ClientSecret string `yaml:"client_secret"`
Scope string `yaml:"scope"`
Name string `yaml:"name"`
AuthURL string `yaml:"auth_url"`
TokenURL string `yaml:"token_url"`
ProfileURL string `yaml:"profile_url"`
ClientID string `yaml:"client_id"`
ClientSecret string `yaml:"client_secret"`
Scope string `yaml:"scope"`
UsernameField string `yaml:"username_field"`
}

// Provider is the OAuth provider.
type Provider struct {
Name string
AuthURL string
TokenURL string
ProfileURL string
ClientID string
ClientSecret string
Scope string
Name string
AuthURL string
TokenURL string
ProfileURL string
ClientID string
ClientSecret string
Scope string
UsernameField string
}

// OAuthToken is the OAuth token.
Expand All @@ -50,15 +52,16 @@ type OAuthToken struct {
}

// NewProvider creates a new OAuth provider.
func NewProvider(name, authURL, tokenURL, profileURL, clientID, clientSecret, scope string) *Provider {
func NewProvider(name, authURL, tokenURL, profileURL, clientID, clientSecret, scope string, usernameField string) *Provider {
return &Provider{
Name: name,
AuthURL: authURL,
TokenURL: tokenURL,
ProfileURL: profileURL,
ClientID: clientID,
ClientSecret: clientSecret,
Scope: scope,
Name: name,
AuthURL: authURL,
TokenURL: tokenURL,
ProfileURL: profileURL,
ClientID: clientID,
ClientSecret: clientSecret,
Scope: scope,
UsernameField: usernameField,
}
}

Expand Down Expand Up @@ -92,6 +95,7 @@ func InitProviders() (map[string]*Provider, error) {
viper.GetString(conf.ClientID),
viper.GetString(conf.ClientSecret),
conf.Scope,
conf.UsernameField,
)
providers[name] = provider
}
Expand Down
18 changes: 6 additions & 12 deletions storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,12 @@ import (
"path/filepath"
"time"

"github.com/ethereum/go-ethereum/common"
"go.vocdoni.io/dvote/db"
"go.vocdoni.io/dvote/db/metadb"
"go.vocdoni.io/dvote/db/prefixeddb"
"go.vocdoni.io/dvote/log"
)

const (
fundedAddressPrefix = "a_"
)

type storage struct {
kv db.Database
waitPeriodSeconds uint64
Expand All @@ -40,12 +35,12 @@ func newStorage(dbType string, dataDir string, waitPeriod time.Duration, dbPrefi
return st, nil
}

// addFundedAddress adds the given address to the funded addresses list, with the current time
// addFundedUserID adds the given userID to the funded list, with the current time
// as the wait period end time.
func (st *storage) addFundedAddress(addr common.Address, authType string) error {
func (st *storage) addFundedUserID(userID []byte, authType string) error {
tx := st.kv.WriteTx()
defer tx.Discard()
key := append([]byte(fundedAddressPrefix), append(addr.Bytes(), []byte(authType)...)...)
key := append(userID, []byte(authType)...)
wp := uint64(time.Now().Unix()) + st.waitPeriodSeconds
wpBytes := make([]byte, 8)
binary.LittleEndian.PutUint64(wpBytes, wp)
Expand All @@ -55,11 +50,10 @@ func (st *storage) addFundedAddress(addr common.Address, authType string) error
return tx.Commit()
}

// checkIsFundedAddress checks if the given address is funded and returns true if it is, within
// checkIsFundedUserID checks if the given text is funded and returns true if it is, within
// the wait period time window. Otherwise, it returns false.
// The second return value is the wait period end time, if the address is funded.
func (st *storage) checkIsFundedAddress(addr common.Address, authType string) (bool, time.Time) {
key := append([]byte(fundedAddressPrefix), append(addr.Bytes(), []byte(authType)...)...)
func (st *storage) checkIsFundedUserID(userID []byte, authType string) (bool, time.Time) {
key := append(userID, []byte(authType)...)
wpBytes, err := st.kv.Get(key)
if err != nil {
return false, time.Time{}
Expand Down