Page Menu
Home
Musing Studio
Search
Configure Global Search
Log In
Files
F10387515
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
8 KB
Subscribers
None
View Options
diff --git a/auth.go b/auth.go
index e66f0bb..ffba97d 100644
--- a/auth.go
+++ b/auth.go
@@ -1,75 +1,77 @@
package writeas
import (
"fmt"
"net/http"
)
// LogIn authenticates a user with Write.as.
// See https://developer.write.as/docs/api/#authenticate-a-user
func (c *Client) LogIn(username, pass string) (*AuthUser, error) {
u := &AuthUser{}
up := struct {
Alias string `json:"alias"`
Pass string `json:"pass"`
}{
Alias: username,
Pass: pass,
}
env, err := c.post("/auth/login", up, u)
if err != nil {
return nil, err
}
var ok bool
if u, ok = env.Data.(*AuthUser); !ok {
return nil, fmt.Errorf("Wrong data returned from API.")
}
+ u.BaseURL = c.BaseUrl()
+
status := env.Code
if status != http.StatusOK {
if status == http.StatusBadRequest {
return nil, fmt.Errorf("Bad request: %s", env.ErrorMessage)
} else if status == http.StatusUnauthorized {
return nil, fmt.Errorf("Incorrect password.")
} else if status == http.StatusNotFound {
return nil, fmt.Errorf("User does not exist.")
} else if status == http.StatusTooManyRequests {
return nil, fmt.Errorf("Stop repeatedly trying to log in.")
}
return nil, fmt.Errorf("Problem authenticating: %d. %v\n", status, err)
}
c.SetToken(u.AccessToken)
return u, nil
}
// LogOut logs the current user out, making the Client's current access token
// invalid.
func (c *Client) LogOut() error {
env, err := c.delete("/auth/me", nil)
if err != nil {
return err
}
status := env.Code
if status != http.StatusNoContent {
if status == http.StatusNotFound {
return fmt.Errorf("Access token is invalid or doesn't exist")
}
return fmt.Errorf("Unable to log out: %v", env.ErrorMessage)
}
// Logout successful, so update the Client
c.token = ""
return nil
}
func (c *Client) isNotLoggedIn(code int) bool {
if c.token == "" {
return false
}
return code == http.StatusUnauthorized
}
diff --git a/user.go b/user.go
index 5973d9c..1e150a5 100644
--- a/user.go
+++ b/user.go
@@ -1,34 +1,35 @@
package writeas
import "time"
type (
// AuthUser represents a just-authenticated user. It contains information
// that'll only be returned once (now) per user session.
AuthUser struct {
+ BaseURL string `json:"baseUrl,omitempty"`
AccessToken string `json:"access_token,omitempty"`
Password string `json:"password,omitempty"`
User *User `json:"user"`
}
// User represents a registered Write.as user.
User struct {
Username string `json:"username"`
Email string `json:"email"`
Created time.Time `json:"created"`
// Optional properties
Subscription *UserSubscription `json:"subscription"`
}
// UserSubscription contains information about a user's Write.as
// subscription.
UserSubscription struct {
Name string `json:"name"`
Begin time.Time `json:"begin"`
End time.Time `json:"end"`
AutoRenew bool `json:"auto_renew"`
Active bool `json:"is_active"`
Delinquent bool `json:"is_delinquent"`
}
)
diff --git a/writeas.go b/writeas.go
index fa87ae1..785c044 100644
--- a/writeas.go
+++ b/writeas.go
@@ -1,199 +1,211 @@
// Package writeas provides the binding for the Write.as API
package writeas
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
"code.as/core/socks"
"github.com/writeas/impart"
)
const (
apiURL = "https://write.as/api"
devAPIURL = "https://development.write.as/api"
torAPIURL = "http://writeas7pm7rcdqg.onion/api"
// Current go-writeas version
Version = "2-dev"
)
// Client is used to interact with the Write.as API. It can be used to make
// authenticated or unauthenticated calls.
type Client struct {
baseURL string
// Access token for the user making requests.
token string
// Client making requests to the API
client *http.Client
// UserAgent overrides the default User-Agent header
UserAgent string
}
// defaultHTTPTimeout is the default http.Client timeout.
const defaultHTTPTimeout = 10 * time.Second
// NewClient creates a new API client. By default, all requests are made
// unauthenticated. To optionally make authenticated requests, call `SetToken`.
//
// c := writeas.NewClient()
// c.SetToken("00000000-0000-0000-0000-000000000000")
func NewClient() *Client {
return NewClientWith(Config{URL: apiURL})
}
// NewTorClient creates a new API client for communicating with the Write.as
// Tor hidden service, using the given port to connect to the local SOCKS
// proxy.
func NewTorClient(port int) *Client {
return NewClientWith(Config{URL: torAPIURL, TorPort: port})
}
// NewDevClient creates a new API client for development and testing. It'll
// communicate with our development servers, and SHOULD NOT be used in
// production.
func NewDevClient() *Client {
return NewClientWith(Config{URL: devAPIURL})
}
// Config configures a Write.as client.
type Config struct {
// URL of the Write.as API service. Defaults to https://write.as/api.
URL string
// If specified, the API client will communicate with the Write.as Tor
// hidden service using the provided port to connect to the local SOCKS
// proxy.
TorPort int
// If specified, requests will be authenticated using this user token.
// This may be provided after making a few anonymous requests with
// SetToken.
Token string
}
// NewClientWith builds a new API client with the provided configuration.
func NewClientWith(c Config) *Client {
if c.URL == "" {
c.URL = apiURL
}
httpClient := &http.Client{Timeout: defaultHTTPTimeout}
if c.TorPort > 0 {
dialSocksProxy := socks.DialSocksProxy(socks.SOCKS5, fmt.Sprintf("127.0.0.1:%d", c.TorPort))
httpClient.Transport = &http.Transport{Dial: dialSocksProxy}
}
return &Client{
client: httpClient,
baseURL: c.URL,
token: c.Token,
}
}
// SetToken sets the user token for all future Client requests. Setting this to
// an empty string will change back to unauthenticated requests.
func (c *Client) SetToken(token string) {
c.token = token
}
// Token returns the user token currently set to the Client.
func (c *Client) Token() string {
return c.token
}
+// SetBaseUrl sets the baseUrl for all future Client requests
+func (c *Client) SetBaseUrl(baseUrl string) {
+ if baseUrl != "" {
+ c.baseURL = baseUrl
+ }
+}
+
+// BaseUrl returns the set baseUrl
+func (c *Client) BaseUrl() string {
+ return c.baseURL
+}
+
func (c *Client) get(path string, r interface{}) (*impart.Envelope, error) {
method := "GET"
if method != "GET" && method != "HEAD" {
return nil, fmt.Errorf("Method %s not currently supported by library (only HEAD and GET).\n", method)
}
return c.request(method, path, nil, r)
}
func (c *Client) post(path string, data, r interface{}) (*impart.Envelope, error) {
b := new(bytes.Buffer)
json.NewEncoder(b).Encode(data)
return c.request("POST", path, b, r)
}
func (c *Client) put(path string, data, r interface{}) (*impart.Envelope, error) {
b := new(bytes.Buffer)
json.NewEncoder(b).Encode(data)
return c.request("PUT", path, b, r)
}
func (c *Client) delete(path string, data map[string]string) (*impart.Envelope, error) {
r, err := c.buildRequest("DELETE", path, nil)
if err != nil {
return nil, err
}
q := r.URL.Query()
for k, v := range data {
q.Add(k, v)
}
r.URL.RawQuery = q.Encode()
return c.doRequest(r, nil)
}
func (c *Client) request(method, path string, data io.Reader, result interface{}) (*impart.Envelope, error) {
r, err := c.buildRequest(method, path, data)
if err != nil {
return nil, err
}
return c.doRequest(r, result)
}
func (c *Client) buildRequest(method, path string, data io.Reader) (*http.Request, error) {
url := fmt.Sprintf("%s%s", c.baseURL, path)
r, err := http.NewRequest(method, url, data)
if err != nil {
return nil, fmt.Errorf("Create request: %v", err)
}
c.prepareRequest(r)
return r, nil
}
func (c *Client) doRequest(r *http.Request, result interface{}) (*impart.Envelope, error) {
resp, err := c.client.Do(r)
if err != nil {
return nil, fmt.Errorf("Request: %v", err)
}
defer resp.Body.Close()
env := &impart.Envelope{
Code: resp.StatusCode,
}
if result != nil {
env.Data = result
err = json.NewDecoder(resp.Body).Decode(&env)
if err != nil {
return nil, err
}
}
return env, nil
}
func (c *Client) prepareRequest(r *http.Request) {
ua := c.UserAgent
if ua == "" {
ua = "go-writeas v" + Version
}
r.Header.Set("User-Agent", ua)
r.Header.Add("Content-Type", "application/json")
if c.token != "" {
r.Header.Add("Authorization", "Token "+c.token)
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Nov 25, 1:59 PM (1 d, 16 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3106698
Attached To
rWGO writeas-go
Event Timeline
Log In to Comment