Page Menu
Home
Musing Studio
Search
Configure Global Search
Log In
Files
F13893740
cli.go
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
8 KB
Subscribers
None
cli.go
View Options
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.2"
)
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"
,
},
cli
.
IntFlag
{
Name
:
"tor-port"
,
Usage
:
"Use a different port to connect to Tor"
,
Value
:
9150
,
},
}
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 via Tor hidden service"
,
},
cli
.
IntFlag
{
Name
:
"tor-port"
,
Usage
:
"Use a different port to connect to Tor"
,
Value
:
9150
,
},
},
},
{
Name
:
"delete"
,
Usage
:
"Delete a post"
,
Action
:
cmdDelete
,
Flags
:
[]
cli
.
Flag
{
cli
.
BoolFlag
{
Name
:
"tor, t"
,
Usage
:
"Delete via Tor hidden service"
,
},
cli
.
IntFlag
{
Name
:
"tor-port"
,
Usage
:
"Use a different port to connect to Tor"
,
Value
:
9150
,
},
},
},
{
Name
:
"update"
,
Usage
:
"Update (overwrite) a post"
,
Action
:
cmdUpdate
,
Flags
:
[]
cli
.
Flag
{
cli
.
BoolFlag
{
Name
:
"tor, t"
,
Usage
:
"Update via Tor hidden service"
,
},
cli
.
IntFlag
{
Name
:
"tor-port"
,
Usage
:
"Use a different port to connect to Tor"
,
Value
:
9150
,
},
},
},
{
Name
:
"get"
,
Usage
:
"Read a raw post"
,
Action
:
cmdGet
,
Flags
:
[]
cli
.
Flag
{
cli
.
BoolFlag
{
Name
:
"tor, t"
,
Usage
:
"Get from Tor hidden service"
,
},
cli
.
IntFlag
{
Name
:
"tor-port"
,
Usage
:
"Use a different port to connect to Tor"
,
Value
:
9150
,
},
},
},
{
Name
:
"add"
,
Usage
:
"Add a post locally"
,
Action
:
cmdAdd
,
},
{
Name
:
"list"
,
Usage
:
"List local posts"
,
Action
:
cmdList
,
Flags
:
[]
cli
.
Flag
{
cli
.
BoolFlag
{
Name
:
"id"
,
Usage
:
"Show list with post IDs (default)"
,
},
cli
.
BoolFlag
{
Name
:
"url"
,
Usage
:
"Show list with URLs"
,
},
},
},
}
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
cmdPost
(
c
*
cli
.
Context
)
{
fullPost
:=
readStdIn
()
tor
:=
c
.
Bool
(
"tor"
)
||
c
.
Bool
(
"t"
)
if
c
.
Int
(
"tor-port"
)
!=
0
{
torPort
=
c
.
Int
(
"tor-port"
)
}
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
==
""
{
fmt
.
Println
(
"usage: writeas delete <postId> [<token>]"
)
os
.
Exit
(
1
)
}
if
token
==
""
{
// Search for the token locally
token
=
tokenFromID
(
friendlyId
)
if
token
==
""
{
fmt
.
Println
(
"Couldn't find an edit token locally. Did you create this post here?"
)
fmt
.
Printf
(
"If you have an edit token, use: writeas delete %s <token>\n"
,
friendlyId
)
os
.
Exit
(
1
)
}
}
tor
:=
c
.
Bool
(
"tor"
)
||
c
.
Bool
(
"t"
)
if
c
.
Int
(
"tor-port"
)
!=
0
{
torPort
=
c
.
Int
(
"tor-port"
)
}
DoDelete
(
friendlyId
,
token
,
tor
)
}
func
cmdUpdate
(
c
*
cli
.
Context
)
{
friendlyId
:=
c
.
Args
().
Get
(
0
)
token
:=
c
.
Args
().
Get
(
1
)
if
friendlyId
==
""
{
fmt
.
Println
(
"usage: writeas update <postId> [<token>]"
)
os
.
Exit
(
1
)
}
if
token
==
""
{
// Search for the token locally
token
=
tokenFromID
(
friendlyId
)
if
token
==
""
{
fmt
.
Println
(
"Couldn't find an edit token locally. Did you create this post here?"
)
fmt
.
Printf
(
"If you have an edit token, use: writeas update %s <token>\n"
,
friendlyId
)
os
.
Exit
(
1
)
}
}
// Read post body
fullPost
:=
readStdIn
()
tor
:=
c
.
Bool
(
"tor"
)
||
c
.
Bool
(
"t"
)
if
c
.
Int
(
"tor-port"
)
!=
0
{
torPort
=
c
.
Int
(
"tor-port"
)
}
DoUpdate
(
fullPost
,
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"
)
if
c
.
Int
(
"tor-port"
)
!=
0
{
torPort
=
c
.
Int
(
"tor-port"
)
}
DoFetch
(
friendlyId
,
tor
)
}
func
cmdAdd
(
c
*
cli
.
Context
)
{
friendlyId
:=
c
.
Args
().
Get
(
0
)
token
:=
c
.
Args
().
Get
(
1
)
if
friendlyId
==
""
||
token
==
""
{
fmt
.
Println
(
"usage: writeas add <postId> <token>"
)
os
.
Exit
(
1
)
}
addPost
(
friendlyId
,
token
)
}
func
cmdList
(
c
*
cli
.
Context
)
{
urls
:=
c
.
Bool
(
"url"
)
ids
:=
c
.
Bool
(
"id"
)
var
p
Post
posts
:=
getPosts
()
for
i
:=
range
*
posts
{
p
=
(
*
posts
)[
len
(
*
posts
)
-
1
-
i
]
if
ids
||
!
urls
{
fmt
.
Printf
(
"%s "
,
p
.
ID
)
}
if
urls
{
fmt
.
Printf
(
"https://write.as/%s "
,
p
.
ID
)
}
fmt
.
Print
(
"\n"
)
}
}
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
len
(
path
)
!=
12
{
// Handle alpha phase HTML-based URLs
path
+=
".txt"
}
if
read
{
u
.
Path
=
"/"
+
path
}
else
{
u
.
Path
=
"/api"
}
client
=
torClient
()
}
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
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"
,
""
)
}
data
.
Add
(
"font"
,
"mono"
)
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
)
nlPos
:=
strings
.
Index
(
string
(
content
),
"\n"
)
url
:=
content
[:
nlPos
]
idPos
:=
strings
.
LastIndex
(
string
(
url
),
"/"
)
+
1
id
:=
string
(
url
[
idPos
:])
token
:=
string
(
content
[
nlPos
+
1
:
len
(
content
)
-
1
])
addPost
(
id
,
token
)
fmt
.
Printf
(
"%s\n"
,
url
)
}
else
{
fmt
.
Printf
(
"Unable to post: %s\n"
,
resp
.
Status
)
}
}
func
DoUpdate
(
post
[]
byte
,
friendlyId
,
token
string
,
tor
bool
)
{
urlStr
,
client
:=
client
(
false
,
tor
,
""
,
fmt
.
Sprintf
(
"id=%s&t=%s"
,
friendlyId
,
token
))
data
:=
url
.
Values
{}
data
.
Set
(
"w"
,
string
(
post
))
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
{
if
tor
{
fmt
.
Println
(
"Post updated via hidden service."
)
}
else
{
fmt
.
Println
(
"Post updated."
)
}
}
else
{
if
DEBUG
{
fmt
.
Printf
(
"Problem updating: %s\n"
,
resp
.
Status
)
}
else
{
fmt
.
Printf
(
"Post doesn't exist, or bad edit token given.\n"
)
}
}
}
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."
)
}
removePost
(
friendlyId
)
}
else
{
if
DEBUG
{
fmt
.
Printf
(
"Problem deleting: %s\n"
,
resp
.
Status
)
}
else
{
fmt
.
Printf
(
"Post doesn't exist, or bad edit token given.\n"
)
}
}
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Thu, Mar 12, 7:02 PM (1 d, 21 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3651528
Attached To
rWCLI writeas-cli
Event Timeline
Log In to Comment