Skip to main content
Glama

Storyden

by Southclaws
Mozilla Public License 2.0
229
github.go4.15 kB
package github import ( "context" "fmt" "net/mail" "strconv" "strings" "time" "github.com/Southclaws/fault" "github.com/Southclaws/fault/fctx" "github.com/Southclaws/fault/fmsg" "github.com/Southclaws/fault/ftag" "github.com/Southclaws/opt" "github.com/google/go-github/v75/github" "golang.org/x/oauth2" oauth2_github "golang.org/x/oauth2/github" "github.com/Southclaws/storyden/app/resources/account" "github.com/Southclaws/storyden/app/resources/account/authentication" "github.com/Southclaws/storyden/app/services/account/register" "github.com/Southclaws/storyden/app/services/authentication/provider/oauth" "github.com/Southclaws/storyden/internal/config" "github.com/Southclaws/storyden/internal/infrastructure/endec" ) var ( service = authentication.ServiceOAuthGitHub tokenType = authentication.TokenTypeOAuth ) type Provider struct { config oauth.Configuration register *register.Registrar ed endec.EncrypterDecrypter } func New( cfg config.Config, register *register.Registrar, ed endec.EncrypterDecrypter, ) (*Provider, error) { if cfg.GitHubEnabled && ed == nil { return nil, fault.New("JWT provider must be enabled by setting JWT_SECRET for GitHub OAuth provider") } return &Provider{ config: oauth.Configuration{ Enabled: cfg.GitHubEnabled, ClientID: cfg.GitHubClientID, ClientSecret: cfg.GitHubClientSecret, }, register: register, ed: ed, }, nil } func (p *Provider) Service() authentication.Service { return service } func (p *Provider) Token() authentication.TokenType { return tokenType } func (p *Provider) Enabled(ctx context.Context) (bool, error) { return p.config.Enabled, nil } func (p *Provider) oauthConfig(redirect string) *oauth2.Config { return &oauth2.Config{ ClientID: p.config.ClientID, ClientSecret: p.config.ClientSecret, Endpoint: oauth2_github.Endpoint, RedirectURL: redirect, Scopes: []string{ "read:user", "user:email", }, } } func (p *Provider) Link(redirectPath string) (string, error) { state, err := p.ed.Encrypt(map[string]any{ "redirect": redirectPath, }, time.Minute*10) if err != nil { return "", fault.Wrap(err) } oac := p.oauthConfig(redirectPath) return oac.AuthCodeURL(state, oauth2.AccessTypeOffline), nil } func (p *Provider) Login(ctx context.Context, state, code string) (*account.Account, error) { c, err := p.ed.Decrypt(state) if err != nil { return nil, fault.Wrap(err, fctx.With(ctx), fmsg.WithDesc("failed to decrypt state value", "This link has expired, please try again."), ) } oac := p.oauthConfig(c["redirect"].(string)) token, err := oac.Exchange(ctx, code, oauth2.AccessTypeOffline) if err != nil { return nil, fault.Wrap(err, fctx.With(ctx), ftag.With(ftag.InvalidArgument), fmsg.WithDesc("failed to exchange code for token", "This login token may have expired, please try again from the start."), ) } client := github.NewClient(nil).WithAuthToken(token.AccessToken) u, _, err := client.Users.Get(ctx, "") if err != nil { return nil, fault.Wrap(err, fctx.With(ctx), fmsg.WithDesc("failed to fetch GitHub user profile", "Unable to retrieve your GitHub profile. This might be due to privacy settings.")) } if u.Login == nil { return nil, fault.New("missing login", ftag.With(ftag.InvalidArgument), fmsg.WithDesc("no username", "The GitHub API did not return a username for this account."), ) } handle := strings.ToLower(*u.Login) name := opt.NewPtr(u.Name).Or(handle) authName := fmt.Sprintf("GitHub (@%s)", handle) if u.Email == nil { return p.register.GetOrCreateViaHandle(ctx, service, authName, strconv.Itoa(int(*u.ID)), token.AccessToken, handle, name, ) } email, err := mail.ParseAddress(*u.Email) if err != nil { return nil, fault.Wrap(err, fctx.With(ctx), fmsg.WithDesc("failed to parse GitHub email address", "The email address from GitHub is invalid. Please check your GitHub account settings.")) } return p.register.GetOrCreateViaEmail(ctx, service, authName, strconv.Itoa(int(*u.ID)), token.AccessToken, handle, name, *email, ) }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Southclaws/storyden'

If you have feedback or need assistance with the MCP directory API, please join our Discord server