Page Menu
Home
Musing Studio
Search
Configure Global Search
Log In
Files
F10669882
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
6 KB
Subscribers
None
View Options
diff --git a/cli.go b/cli.go
index c7a0645..eee578d 100644
--- a/cli.go
+++ b/cli.go
@@ -1,254 +1,285 @@
package main
import (
"bufio"
"bytes"
"fmt"
"github.com/codegangsta/cli"
"github.com/writeas/libwriteprivate"
"io"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"strconv"
)
const (
apiUrl = "http://i.write.as"
hiddenApiUrl = "http://writeas7pm7rcdqg.onion"
readApiUrl = "http://i.write.as"
VERSION = "0.1.0"
)
func main() {
app := cli.NewApp()
app.Name = "writeas"
app.Version = VERSION
app.Usage = "Simple text pasting and publishing"
app.Authors = []cli.Author{
{
Name: "Write.as",
Email: "hello@write.as",
},
}
app.Action = cmdPost
app.Flags = []cli.Flag{
cli.BoolFlag{
Name: "tor, t",
Usage: "Perform action on Tor hidden service",
},
}
app.Commands = []cli.Command{
{
Name: "post",
Usage: "Alias for default action: create post from stdin",
Action: cmdPost,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "tor, t",
Usage: "Post to Tor hidden service",
},
},
},
{
Name: "delete",
Usage: "Delete a post",
Action: cmdDelete,
+ Flags: []cli.Flag{
+ cli.BoolFlag{
+ Name: "tor, t",
+ Usage: "Delete from Tor hidden service",
+ },
+ },
},
{
Name: "get",
Usage: "Read a raw post",
Action: cmdGet,
+ Flags: []cli.Flag{
+ cli.BoolFlag{
+ Name: "tor, t",
+ Usage: "Get from Tor hidden service",
+ },
+ },
},
}
app.Run(os.Args)
}
func readStdIn() []byte {
numBytes, numChunks := int64(0), int64(0)
r := bufio.NewReader(os.Stdin)
fullPost := []byte{}
buf := make([]byte, 0, 1024)
for {
n, err := r.Read(buf[:cap(buf)])
buf = buf[:n]
if n == 0 {
if err == nil {
continue
}
if err == io.EOF {
break
}
log.Fatal(err)
}
numChunks++
numBytes += int64(len(buf))
fullPost = append(fullPost, buf...)
if err != nil && err != io.EOF {
log.Fatal(err)
}
}
return fullPost
}
func check(err error) {
if err != nil {
fmt.Printf("%s\n", err)
os.Exit(1)
}
}
func getPass() []byte {
// TODO: don't show passphrase in the terminal
var p string
_, err := fmt.Scanln(&p)
check(err)
return []byte(p)
}
func cmdPost(c *cli.Context) {
fullPost := readStdIn()
// Encrypt post, if needed
encrypt := c.Bool("encrypt") || c.Bool("e")
if encrypt {
// Prompt for passphrase
fmt.Printf("Enter a passphrase: ")
pass := getPass()
var err error
fullPost, err = writeprivate.Encrypt(pass, fullPost)
check(err)
}
tor := c.Bool("tor") || c.Bool("t")
if tor {
fmt.Println("Posting to hidden service...")
} else {
fmt.Println("Posting...")
}
DoPost(fullPost, encrypt, tor)
}
func cmdDelete(c *cli.Context) {
friendlyId := c.Args().Get(0)
token := c.Args().Get(1)
if friendlyId == "" || token == "" {
fmt.Println("usage: writeas delete <postId> <token>")
os.Exit(1)
}
- DoDelete(friendlyId, token)
+
+ tor := c.Bool("tor") || c.Bool("t")
+
+ DoDelete(friendlyId, token, tor)
}
func cmdGet(c *cli.Context) {
friendlyId := c.Args().Get(0)
if friendlyId == "" {
fmt.Println("usage: writeas get <postId>")
os.Exit(1)
}
- DoFetch(friendlyId)
+
+ tor := c.Bool("tor") || c.Bool("t")
+
+ DoFetch(friendlyId, tor)
}
func cmdDecrypt(c *cli.Context) {
// TODO: Fetch post
// TODO: Prompt for passphrase
// TODO: Decrypt and output
}
-func DoFetch(friendlyId string) {
- var path string
- path = friendlyId
- /*
- if len(friendlyId) == 12 {
- // Original (pre-alpha) plain text URLs
- path = friendlyId
- } else if len(friendlyId) == 13 {
- // Alpha phase HTML-based URLs
- path = friendlyId + ".txt"
+func client(read, tor bool, path, query string) (string, *http.Client) {
+ var u *url.URL
+ var client *http.Client
+ if tor {
+ u, _ = url.ParseRequestURI(hiddenApiUrl)
+ if read {
+ u.Path = "/" + path
} else {
- // Fallback path. Plan is to always support .txt file for raw files
- path = friendlyId + ".txt"
+ u.Path = "/api"
}
- */
-
- u, _ := url.ParseRequestURI(readApiUrl)
- u.Path = "/" + path
+ client = torClient()
+ } else {
+ if read {
+ u, _ = url.ParseRequestURI(readApiUrl)
+ } else {
+ u, _ = url.ParseRequestURI(apiUrl)
+ }
+ u.Path = "/" + path
+ client = &http.Client{}
+ }
+ if query != "" {
+ u.RawQuery = query
+ }
urlStr := fmt.Sprintf("%v", u)
+ return urlStr, client
+}
+
+func DoFetch(friendlyId string, tor bool) {
+ path := friendlyId
+ if len(friendlyId) == 12 {
+ // Original (pre-alpha) plain text URLs
+ path = friendlyId
+ } else if len(friendlyId) == 13 {
+ // Alpha phase HTML-based URLs
+ path = friendlyId + ".txt"
+ } else {
+ // Fallback path. Plan is to always support .txt file for raw files
+ path = friendlyId + ".txt"
+ }
+
+ urlStr, client := client(true, tor, path, "")
+
r, _ := http.NewRequest("GET", urlStr, nil)
r.Header.Add("User-Agent", "writeas-cli v"+VERSION)
- resp, err := http.DefaultClient.Do(r)
+ resp, err := client.Do(r)
check(err)
defer resp.Body.Close()
if resp.StatusCode == http.StatusOK {
content, err := ioutil.ReadAll(resp.Body)
check(err)
fmt.Printf("%s\n", string(content))
} else {
fmt.Printf("Problem getting post: %s\n", resp.Status)
}
}
func DoPost(post []byte, encrypt, tor bool) {
data := url.Values{}
data.Set("w", string(post))
if encrypt {
data.Add("e", "")
}
- var u *url.URL
- var client *http.Client
- if tor {
- u, _ = url.ParseRequestURI(hiddenApiUrl)
- u.Path = "/api"
- client = torClient()
- } else {
- u, _ = url.ParseRequestURI(apiUrl)
- u.Path = "/"
- client = &http.Client{}
- }
- urlStr := fmt.Sprintf("%v", u)
+ urlStr, client := client(false, tor, "", "")
r, _ := http.NewRequest("POST", urlStr, bytes.NewBufferString(data.Encode()))
r.Header.Add("Content-Type", "application/x-www-form-urlencoded")
r.Header.Add("Content-Length", strconv.Itoa(len(data.Encode())))
resp, err := client.Do(r)
check(err)
defer resp.Body.Close()
if resp.StatusCode == http.StatusOK {
content, err := ioutil.ReadAll(resp.Body)
check(err)
fmt.Printf("%s\n", string(content))
} else {
fmt.Printf("Unable to post: %s\n", resp.Status)
}
}
-func DoDelete(friendlyId, token string) {
- u, _ := url.ParseRequestURI(apiUrl)
- u.Path = "/"
- u.RawQuery = fmt.Sprintf("id=%s&t=%s", friendlyId, token)
- urlStr := fmt.Sprintf("%v", u)
+func DoDelete(friendlyId, token string, tor bool) {
+ urlStr, client := client(false, tor, "", fmt.Sprintf("id=%s&t=%s", friendlyId, token))
r, _ := http.NewRequest("DELETE", urlStr, nil)
r.Header.Add("Content-Type", "application/x-www-form-urlencoded")
- resp, err := http.DefaultClient.Do(r)
+ resp, err := client.Do(r)
check(err)
defer resp.Body.Close()
if resp.StatusCode == http.StatusOK {
- fmt.Println("Post deleted.")
+ if tor {
+ fmt.Println("Post deleted from hidden service.")
+ } else {
+ fmt.Println("Post deleted.")
+ }
} else {
fmt.Printf("Problem deleting: %s\n", resp.Status)
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, May 16, 6:13 PM (1 d, 12 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3240317
Attached To
rWCLI writeas-cli
Event Timeline
Log In to Comment