Page MenuHomeMusing Studio

No OneTemporary

diff --git a/cli.go b/cli.go
index 8e98fee..937afaf 100644
--- a/cli.go
+++ b/cli.go
@@ -1,269 +1,289 @@
package main
import (
"bufio"
"bytes"
"fmt"
"github.com/codegangsta/cli"
"io"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"strconv"
+ "strings"
)
const (
apiUrl = "http://i.write.as"
hiddenApiUrl = "http://writeas7pm7rcdqg.onion"
readApiUrl = "http://i.write.as"
VERSION = "0.1.0"
)
func main() {
+ initialize()
+
+ // Run the app
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 initialize() {
+ // Ensure we have a data directory to use
+ if !dataDirExists() {
+ createDataDir()
+ }
+}
+
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()
tor := c.Bool("tor") || c.Bool("t")
if tor {
fmt.Println("Posting to hidden service...")
} else {
fmt.Println("Posting...")
}
DoPost(fullPost, false, 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)
}
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)
}
tor := c.Bool("tor") || c.Bool("t")
DoFetch(friendlyId, tor)
}
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 {
u.Path = "/api"
}
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 := 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 if resp.StatusCode == http.StatusNotFound {
fmt.Printf("Post not found.\n")
} 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", "")
}
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))
+
+ nlPos := strings.Index(string(content), "\n")
+ url := content[:nlPos]
+ idPos := strings.LastIndex(string(url), "/") + 1
+ id := string(url[idPos:])
+ token := string(content[nlPos+1:])
+
+ addPost(id, token)
+
+ fmt.Printf("%s\n", url)
} else {
fmt.Printf("Unable to post: %s\n", resp.Status)
}
}
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 := client.Do(r)
check(err)
defer resp.Body.Close()
if resp.StatusCode == http.StatusOK {
if tor {
fmt.Println("Post deleted from hidden service.")
} else {
fmt.Println("Post deleted.")
}
} else {
fmt.Printf("Problem deleting: %s\n", resp.Status)
}
}
diff --git a/config.go b/config.go
new file mode 100644
index 0000000..51e3a19
--- /dev/null
+++ b/config.go
@@ -0,0 +1,7 @@
+// +build !debug
+
+package main
+
+const (
+ DEBUG = false
+)
diff --git a/config_debug.go b/config_debug.go
new file mode 100644
index 0000000..81353ef
--- /dev/null
+++ b/config_debug.go
@@ -0,0 +1,7 @@
+// +build debug
+
+package main
+
+const (
+ DEBUG = true
+)
diff --git a/posts.go b/posts.go
new file mode 100644
index 0000000..75a08ed
--- /dev/null
+++ b/posts.go
@@ -0,0 +1,46 @@
+package main
+
+import (
+ "fmt"
+ "github.com/writeas/writeas-cli/utils"
+ "os"
+ "path/filepath"
+)
+
+const (
+ POSTS_FILE = "posts.psv"
+ SEPARATOR = `|`
+)
+
+func userDataDir() string {
+ return filepath.Join(parentDataDir(), DATA_DIR_NAME)
+}
+
+func dataDirExists() bool {
+ return fileutils.Exists(userDataDir())
+}
+
+func createDataDir() {
+ err := os.Mkdir(userDataDir(), 0700)
+ if err != nil && DEBUG {
+ panic(err)
+ }
+}
+
+func addPost(id, token string) {
+ f, err := os.OpenFile(filepath.Join(userDataDir(), POSTS_FILE), os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0600)
+ if err != nil {
+ if DEBUG {
+ panic(err)
+ } else {
+ return
+ }
+ }
+ defer f.Close()
+
+ l := fmt.Sprintf("%s%s%s\n", id, SEPARATOR, token)
+
+ if _, err = f.WriteString(l); err != nil && DEBUG {
+ panic(err)
+ }
+}
diff --git a/posts_nix.go b/posts_nix.go
new file mode 100644
index 0000000..fb1fabc
--- /dev/null
+++ b/posts_nix.go
@@ -0,0 +1,18 @@
+// +build !windows
+
+package main
+
+import (
+ "github.com/mitchellh/go-homedir"
+)
+
+const DATA_DIR_NAME = ".writeas"
+
+func parentDataDir() string {
+ dir, err := homedir.Dir()
+ if err != nil {
+ panic(err)
+ }
+
+ return dir
+}
diff --git a/posts_win.go b/posts_win.go
new file mode 100644
index 0000000..3166372
--- /dev/null
+++ b/posts_win.go
@@ -0,0 +1,13 @@
+// +build windows
+
+package main
+
+import (
+ "os"
+)
+
+const DATA_DIR_NAME = "Write.as"
+
+func parentDataDir() string {
+ return os.Getenv("APPDATA")
+}
diff --git a/utils/fileutils.go b/utils/fileutils.go
new file mode 100644
index 0000000..c0b4d08
--- /dev/null
+++ b/utils/fileutils.go
@@ -0,0 +1,13 @@
+package fileutils
+
+import (
+ "os"
+)
+
+// Exists returns whether or not the given file exists
+func Exists(p string) bool {
+ if _, err := os.Stat(p); err == nil {
+ return true
+ }
+ return false
+}

File Metadata

Mime Type
text/x-diff
Expires
Fri, May 16, 8:05 PM (8 h, 14 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3240424

Event Timeline