diff --git a/mastodon/accounts.go b/mastodon/accounts.go index acf1d04..76b72b6 100644 --- a/mastodon/accounts.go +++ b/mastodon/accounts.go @@ -3,10 +3,13 @@ package mastodon import ( "context" "fmt" + "encoding/json" "net/http" "net/url" "strconv" "time" + "strings" + "path" ) type AccountPleroma struct { @@ -59,6 +62,71 @@ type AccountSource struct { Fields *[]Field `json:"fields"` } +type RegisterCredintals struct { + http.Client + Server string + App *Application + Reason string + Username string + Email string + Password string + Agreement bool + Locale string +} + +// Use for register account on GoToSocial +type Registred struct { + AccessToken string `json:"access_token"` + CreatedAt int64 `json:"created_at"` + Scope string `json:"scope"` + TokenType string `json:"token_type"` +} + + +// RegisterAccount create new account +func RegisterAccount(ctx context.Context, instance string, reason string, username string, email string, password string, agreement bool, locale string, registerCrendintals RegisterCredintals, bearer string) (*string, error) { + var registred Registred + params := url.Values{} + params.Set("reason", reason) + params.Set("username", username) + params.Set("email", email) + params.Set("password", password) + params.Set("agreement", strconv.FormatBool(agreement)) + params.Set("locale", locale) + u, err := url.Parse("https://" + instance) + if err != nil { + return nil, err + } + u.Path = path.Join(u.Path, "/api/v1/accounts") + + req, err := http.NewRequest(http.MethodPost, u.String(), strings.NewReader(params.Encode())) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + req.Header.Set("Authorization", "Bearer "+bearer) + resp, err := registerCrendintals.Do(req) + fmt.Println(req) + fmt.Println(resp) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, parseAPIError("bad request", resp) + } + + err = json.NewDecoder(resp.Body).Decode(®istred) + fmt.Println(resp.Body) + if err != nil { + return nil, err + } + return ®istred.AccessToken, nil +} + + // GetAccount return Account. func (c *Client) GetAccount(ctx context.Context, id string) (*Account, error) { var account Account diff --git a/mastodon/apps.go b/mastodon/apps.go index 4065ebf..ca24e0b 100644 --- a/mastodon/apps.go +++ b/mastodon/apps.go @@ -48,7 +48,6 @@ func RegisterApp(ctx context.Context, appConfig *AppConfig) (*Application, error params.Set("redirect_uris", appConfig.RedirectURIs) } params.Set("scopes", appConfig.Scopes) - params.Set("website", "https://gitea.phreedom.club/localhost_frssoft/bloat/src/branch/localhost_custom") u, err := url.Parse(appConfig.Server) if err != nil { @@ -71,7 +70,7 @@ func RegisterApp(ctx context.Context, appConfig *AppConfig) (*Application, error if resp.StatusCode != http.StatusOK { return nil, parseAPIError("bad request", resp) } - + var app Application err = json.NewDecoder(resp.Body).Decode(&app) if err != nil { @@ -94,3 +93,50 @@ func RegisterApp(ctx context.Context, appConfig *AppConfig) (*Application, error return &app, nil } + +type AppAuth struct { + http.Client +} + +// RegisterApp make auth application and return app token. +func AuthApp(ctx context.Context, appConfig *Application, instance string) (*string, error) { + var appAuth AppAuth + params := url.Values{} + params.Set("client_id", appConfig.ClientID) + params.Set("client_secret", appConfig.ClientSecret) + params.Set("redirect_uris", "urn:ietf:wg:oauth:2.0:oob") + params.Set("grant_type", "client_credentials") + params.Set("scope", "read write follow") + + u, err := url.Parse("https://" + instance) + if err != nil { + return nil, err + } + u.Path = path.Join(u.Path, "/oauth/token") + + req, err := http.NewRequest(http.MethodPost, u.String(), strings.NewReader(params.Encode())) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + resp, err := appAuth.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, parseAPIError("bad request", resp) + } + + var res struct { + AccessToken string `json:"access_token"` + } + err = json.NewDecoder(resp.Body).Decode(&res) + if err != nil { + return nil, err + } + + return &res.AccessToken, nil +} diff --git a/mastodon/mastodon.go b/mastodon/mastodon.go index 75e029b..3c2a6bb 100644 --- a/mastodon/mastodon.go +++ b/mastodon/mastodon.go @@ -202,6 +202,8 @@ func (c *Client) Authenticate(ctx context.Context, username, password string) er return c.authenticate(ctx, params) } + + // AuthenticateToken logs in using a grant token returned by Application.AuthURI. // // redirectURI should be the same as Application.RedirectURI. diff --git a/service/service.go b/service/service.go index f8e3ff2..550d49d 100644 --- a/service/service.go +++ b/service/service.go @@ -920,6 +920,72 @@ func (s *service) Signin(c *client, code string) (err error) { return c.setSession(c.s) } +func (s *service) NewSessionRegister(c *client, instance string, reason string, username string, email string, password string, agreement bool, locale string, registerCredintals mastodon.RegisterCredintals) (rurl string, sess *model.Session, err error) { + var instanceURL string + if strings.HasPrefix(instance, "https://") { + instanceURL = instance + instance = strings.TrimPrefix(instance, "https://") + } else { + instanceURL = "https://" + instance + } + + sid, err := util.NewSessionID() + if err != nil { + return + } + csrf, err := util.NewCSRFToken() + if err != nil { + return + } + + app, err := mastodon.RegisterApp(c.ctx, &mastodon.AppConfig{ + Server: instanceURL, + ClientName: s.cname, + Scopes: s.cscope, + Website: s.cwebsite, + RedirectURIs: s.cwebsite + "/oauth_callback", + }) + if err != nil { + return + } + registerCredintals.App = app + bearer, err := mastodon.AuthApp(c.ctx, app, instance) + if err != nil { + return + } + token, err := mastodon.RegisterAccount(c.ctx, instance, reason, username, email, password, agreement, locale, registerCredintals, *bearer) + + if err != nil { + return + } + sess = &model.Session{ + ID: sid, + Instance: instance, + UserID: "1", + ClientID: app.ClientID, + ClientSecret: app.ClientSecret, + AccessToken: *token, + CSRFToken: csrf, + Settings: *model.NewSettings(), + } + + u, err := url.Parse("/oauth/authorize") + if err != nil { + return + } + + q := make(url.Values) + q.Set("scope", "read write follow") + q.Set("client_id", app.ClientID) + q.Set("response_type", "code") + q.Set("redirect_uri", s.cwebsite+"/oauth_callback") + u.RawQuery = q.Encode() + + rurl = instanceURL + u.String() + return +} + + func (s *service) Post(c *client, content string, replyToID string, format string, visibility string, isNSFW bool, spoilerText string, files []*multipart.FileHeader, edit string) (id string, err error) { diff --git a/service/transport.go b/service/transport.go index 697281f..6b20559 100644 --- a/service/transport.go +++ b/service/transport.go @@ -254,6 +254,32 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { return nil }, NOAUTH, HTML) + signup := handle(func(c *client) error { + instance := c.r.FormValue("instanceup") + reason := c.r.FormValue("reason") + username := c.r.FormValue("username") + email := c.r.FormValue("email") + password := c.r.FormValue("password") + agreement := c.r.FormValue("agreement") == "true" + locale := c.r.FormValue("locale") + url, sess, err := s.NewSessionRegister(c, instance, reason, username, email, password, agreement, locale, mastodon.RegisterCredintals{ + Server: "https://"+instance, + Reason: reason, + Username: username, + Email: email, + Password: password, + Agreement: agreement, + Locale: locale, + }) + if err != nil { + return err + } + c.setSession(sess) + url = "/confirmation" + c.redirect(url) + return nil + }, NOAUTH, HTML) + oauthCallback := handle(func(c *client) error { q := c.r.URL.Query() token := q.Get("code") @@ -786,6 +812,7 @@ func NewHandler(s *service, logger *log.Logger, staticDir string) http.Handler { r.HandleFunc("/settings", settingsPage).Methods(http.MethodGet) r.HandleFunc("/filters", filtersPage).Methods(http.MethodGet) r.HandleFunc("/signin", signin).Methods(http.MethodPost) + r.HandleFunc("/signup", signup).Methods(http.MethodPost) r.HandleFunc("/oauth_callback", oauthCallback).Methods(http.MethodGet) r.HandleFunc("/post", post).Methods(http.MethodPost) r.HandleFunc("/like/{id}", like).Methods(http.MethodPost) diff --git a/templates/signin.tmpl b/templates/signin.tmpl index c7699f7..5d66772 100644 --- a/templates/signin.tmpl +++ b/templates/signin.tmpl @@ -18,6 +18,39 @@ git.freesoftwareextremist.com/bloat for more details.

+
+Sign up +

+

+ Enter the domain name of your instance to continue +
+ +
+ Enter the reason why you want register +
+ +
+ The desired username for the account +
+ +
+ The email address to be used for login +
+ +
+ The password to be used for login (Please use strong password!) +
+ +
+ You agrees to the terms, conditions, and policies of the instance +
+ + +
+ +
+

+
{{template "footer.tmpl"}} {{end}}