make dep prune things

This commit is contained in:
Cadey Ratio 2017-12-11 10:38:19 -08:00
parent 71e9986283
commit e3a389dde4
6045 changed files with 9 additions and 2981974 deletions

View File

@ -108,6 +108,15 @@ func buildBins(goos, goarch string) {
}
}
// Dep reruns `dep`.
func Dep() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
shouldWork(ctx, nil, wd, "dep", "ensure")
shouldWork(ctx, nil, wd, "dep", "prune")
}
// Docker builds docker images
func Docker() {
ctx, cancel := context.WithCancel(context.Background())

View File

@ -1,56 +0,0 @@
package main
import (
"flag"
"fmt"
"log"
"os"
"path/filepath"
_ "github.com/Xe/gopreload"
)
var (
pkgName = flag.String("pkg", "", "package to underscore import")
destPkgName = flag.String("dest", "", "destination package to generate")
)
const codeTemplate = `//+build go1.8
package main
import _ "$PACKAGE_PATH"`
func main() {
flag.Parse()
if *pkgName == "" || *destPkgName == "" {
log.Fatal("must set -pkg and -dest")
}
srcDir := filepath.Join(os.Getenv("GOPATH"), "src", *destPkgName)
err := os.MkdirAll(srcDir, os.ModePerm)
if err != nil {
log.Fatal(err)
}
fout, err := os.Create(srcDir + "/main.go")
if err != nil {
log.Fatal(err)
}
defer fout.Close()
codeBody := os.Expand(codeTemplate, func(s string) string {
if s == "PACKAGE_PATH" {
return *pkgName
}
return "no idea man"
})
fmt.Fprintln(fout, codeBody)
fmt.Println("To build this plugin: ")
fmt.Println(" $ go build -buildmode plugin -o /path/to/output.so " + *destPkgName)
}

View File

@ -1,5 +0,0 @@
//+build go1.8
package main
import _ "github.com/go-sql-driver/mysql"

View File

@ -1,5 +0,0 @@
//+build go1.8
package main
import _ "github.com/lib/pq"

View File

@ -1,5 +0,0 @@
//+build go1.8
package main
import _ "github.com/mattn/go-sqlite3"

View File

@ -1,56 +0,0 @@
# manhole
An opinionated HTTP manhole into Go processes.
## Assumptions This Package Makes
- Make each server instance have a unique HTTP port that is randomized by default.
This makes it very hard to accidentally route this manhole to the outside world.
If more assurance is required I personally suggest using [yubikey totp][yktotp],
but do research.
- Application code does not touch [`http.DefaultServeMux`][default-servemux]'. This is so that
administative control rods can be dynamically flipped in the case they are
needed.
- [pprof][pprof] endpoints added to `http.DefaultServeMux`. This allows easy
access to [pprof runtime tracing][pprof-tracing] to debug issues on long-running
applications like HTTP services.
- Make the manhole slightly inconvenient to put into place in production. This
helps make sure that this tool remains a debugging tool and not a part of a
long-term production rollout.
## Usage
Compile this as a plugin:
```console
$ go get -d github.com/Xe/gopreload/manhole
$ go build -buildmode plugin -o manhole.so github.com/Xe/gopreload/manhole
```
Then add [`gopreload`][gopreload] to your application:
```go
// gopreload.go
package main
/*
This file is separate to make it very easy to both add into an application, but
also very easy to remove.
*/
import _ "github.com/Xe/gopreload"
```
And at runtime add the `manhole.so` file you created earlier to the target system
somehow and add the following environment variable to its run configuration:
```sh
GO_PRELOAD=/path/to/manhole.so
```
---
[pprof]: https://godoc.org/net/http/pprof
[default-servemux]: https://godoc.org/net/http#pkg-variables
[yktotp]: https://github.com/GeertJohan/yubigo
[gopreload]: https://github.com/Xe/gopreload

View File

@ -1,22 +0,0 @@
package main
import (
"log"
"net"
"net/http"
_ "net/http/pprof"
"net/rpc"
)
func init() {
l, err := net.Listen("tcp", "127.0.0.2:0")
if err != nil {
log.Printf("manhole: cannot bind to 127.0.0.2:0: %v", err)
return
}
log.Printf("manhole: Now listening on http://%s", l.Addr())
rpc.HandleHTTP()
go http.Serve(l, nil)
}

View File

@ -1,55 +0,0 @@
package main
import (
"fmt"
"math/rand"
"net/http"
"runtime"
"time"
_ "github.com/Xe/gopreload"
"github.com/Xe/ln"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
spew()
ln.Log(ln.F{"action": "gc_spew", "who": r.RemoteAddr})
fmt.Fprintln(w, "done")
})
http.ListenAndServe(":9184", nil)
}
func makeBuffer() []byte {
return make([]byte, rand.Intn(5000000)+5000000)
}
func spew() {
pool := make([][]byte, 20)
var m runtime.MemStats
makes := 0
for _ = range make([]struct{}, 50) {
b := makeBuffer()
makes += 1
i := rand.Intn(len(pool))
pool[i] = b
time.Sleep(time.Millisecond * 250)
bytes := 0
for i := 0; i < len(pool); i++ {
if pool[i] != nil {
bytes += len(pool[i])
}
}
runtime.ReadMemStats(&m)
fmt.Printf("%d,%d,%d,%d,%d,%d\n", m.HeapSys, bytes, m.HeapAlloc,
m.HeapIdle, m.HeapReleased, makes)
}
}

View File

@ -1,36 +0,0 @@
package main
import (
"runtime"
"time"
"github.com/Xe/ln"
)
func init() {
ln.Log(ln.F{
"action": "started_up",
"every": "20_seconds",
"what": "gc_metrics",
})
go func() {
for {
time.Sleep(20 * time.Second)
gatherMetrics()
}
}()
}
func gatherMetrics() {
stats := &runtime.MemStats{}
runtime.ReadMemStats(stats)
ln.Log(ln.F{
"gc-collections": stats.NumGC,
"gc-stw-pause-total": stats.PauseTotalNs,
"live-object-count": stats.Mallocs - stats.Frees,
"heap-bytes": stats.Alloc,
"stack-bytes": stats.StackInuse,
})
}

View File

@ -1,51 +0,0 @@
// +build ignore
package main
import (
"context"
"flag"
"net/http"
"time"
"github.com/Xe/ln"
"github.com/Xe/ln/ex"
"github.com/facebookgo/flagenv"
"golang.org/x/net/trace"
)
var (
port = flag.String("port", "2145", "http port to listen on")
tracingFamily = flag.String("trace-family", "ln example", "tracing family to use for x/net/trace")
)
func main() {
flagenv.Parse()
flag.Parse()
ln.DefaultLogger.Filters = append(ln.DefaultLogger.Filters, ex.NewGoTraceLogger())
http.HandleFunc("/", handleIndex)
http.ListenAndServe(":"+*port, middlewareSpan(ex.HTTPLog(http.DefaultServeMux)))
}
func middlewareSpan(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
sp := trace.New(*tracingFamily, "HTTP request")
defer sp.Finish()
ctx, cancel := context.WithTimeout(r.Context(), 30*time.Second)
defer cancel()
ctx = trace.NewContext(ctx, sp)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
func handleIndex(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
ln.Log(ctx, ln.Action("index"), ln.F{"there_is": "no_danger"})
http.Error(w, "There is no danger citizen", http.StatusOK)
}

View File

@ -1,3 +0,0 @@
# farbfeld filters
Filters and tools for http://tools.suckless.org/farbfeld/

View File

@ -1,43 +0,0 @@
package main
import (
"flag"
"image"
"log"
"os"
"runtime"
"github.com/fogleman/primitive/primitive"
farbfeld "github.com/hullerob/go.farbfeld"
)
var (
shapeCount = flag.Int("count", 150, "number of shapes used")
repeatShapeCount = flag.Int("repeat-count", 0, "number of extra shapes drawn in each step")
alpha = flag.Int("alpha", 128, "alpha of all shapes")
)
func stepImg(img image.Image, count int) image.Image {
bg := primitive.MakeColor(primitive.AverageImageColor(img))
model := primitive.NewModel(img, bg, 512, runtime.NumCPU())
for range make([]struct{}, count) {
model.Step(primitive.ShapeTypeTriangle, *alpha, *repeatShapeCount)
}
return model.Context.Image()
}
func main() {
flag.Parse()
img, err := farbfeld.Decode(os.Stdin)
if err != nil {
log.Fatal(err)
}
err = farbfeld.Encode(os.Stdout, stepImg(img, *shapeCount))
if err != nil {
log.Fatal(err)
}
}

View File

@ -1,10 +0,0 @@
b572f0728b691aae4256edb2e408279146eafe52 github.com/hullerob/go.farbfeld
ee8994ff90057955c428a5a949da5d064bf3ce6b github.com/fogleman/gg
80f39ceaa8f4c66acb28aba6abe6b15128c06113 github.com/fogleman/primitive/primitive
bcfeb16b74e8aea9e2fe043406f2ef74b1cb0759 github.com/golang/freetype/raster
bcfeb16b74e8aea9e2fe043406f2ef74b1cb0759 github.com/golang/freetype/truetype
426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/draw
426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/font
426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/font/basicfont
426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/math/f64
426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/math/fixed

View File

@ -1 +0,0 @@
amerge

View File

@ -1,4 +0,0 @@
amerge
======
Utility for scraping and (later) merging atheme databases.

View File

@ -1,591 +0,0 @@
package main
import (
"bufio"
"errors"
"fmt"
"log"
"os"
"strconv"
"strings"
)
var (
NoSuchAcctErr = errors.New("There is no such account by that name")
NoSuchChanErr = errors.New("There is no such channel by that name")
NoSuchGroupErr = errors.New("There is no such group by that name")
)
type Database struct {
Version string
ModuleDeps []*Line
LastUID string
LastKID int
LastXID int
LastQID int
Accounts map[string]*Account
Channels map[string]*Channel
Bots map[string]*Bot
Groups map[string]*Group
Names map[string]*Name
Badwords []Badword
Klines []Kline
ConnectInfos []ConnectInfo
HostOffers []HostOffer
HostRequests []HostRequest
ClonesExemptions []ClonesExemption
Rwatches []Line
lines []*Line
file *bufio.Scanner
}
func NewDatabase(fname string) (db *Database, err error) {
fin, err := os.Open(fname)
if err != nil {
return
}
db = &Database{
Accounts: make(map[string]*Account),
Channels: make(map[string]*Channel),
Bots: make(map[string]*Bot),
Groups: make(map[string]*Group),
Names: make(map[string]*Name),
}
db.file = bufio.NewScanner(fin)
for db.file.Scan() {
rawline := db.file.Text()
l := &Line{}
split := strings.Split(rawline, " ")
l.Verb = split[0]
l.Args = split[1:]
db.lines = append(db.lines, l)
switch l.Verb {
case "DBV": // Database version
db.Version = l.Args[0]
case "MDEP": // Module dependency
db.ModuleDeps = append(db.ModuleDeps, l)
case "LUID": // Last used UID for accounts
db.LastUID = l.Args[0]
case "MU": // Create a user account
a := &Account{
Name: l.Args[1],
UID: l.Args[0],
Email: l.Args[3],
Password: l.Args[2],
Regtime: l.Args[4],
LastSeenTime: l.Args[5],
Metadata: make(map[string]string),
}
db.Accounts[strings.ToUpper(a.Name)] = a
case "MDU": // User metadata
account, err := db.GetAccount(l.Args[0])
if err != nil {
log.Panicf("Tried to read account %s but got %#v???", l.Args[0], err)
}
account.Metadata[l.Args[1]] = strings.Join(l.Args[2:], " ")
case "AC": // Account access rule (prevents nickserv protections for a mask)
account, err := db.GetAccount(l.Args[0])
if err != nil {
log.Panicf("Tried to read account %s but got %#v???", l.Args[0], err)
}
ac := Access{
AccountName: l.Args[0],
Mask: l.Args[1],
}
account.AccessList = append(account.AccessList, ac)
case "MI": // MemoServ IGNORE for a user
account, err := db.GetAccount(l.Args[0])
if err != nil {
log.Panicf("Tried to read account %s but got %#v???", l.Args[0], err)
}
account.Ignores = append(account.Ignores, l.Args[1])
case "MN": // Account nickname in nick group
account, err := db.GetAccount(l.Args[0])
if err != nil {
log.Panicf("Tried to read account %s but got %#v???", l.Args[0], err)
}
gn := GroupedNick{
Account: l.Args[0],
Name: l.Args[1],
Regtime: l.Args[2],
Seentime: l.Args[3],
}
account.Nicks = append(account.Nicks, gn)
case "MCFP": // Certificate Fingerprint
account, err := db.GetAccount(l.Args[0])
if err != nil {
log.Panicf("Tried to read account %s but got %#v???", l.Args[0], err)
}
account.CertFP = append(account.CertFP, l.Args[1])
case "ME": // Memo in user's inbox
account, err := db.GetAccount(l.Args[0])
if err != nil {
log.Panicf("Tried to read account %s but got %#v???", l.Args[0], err)
}
m := Memo{
Inbox: l.Args[0],
From: l.Args[1],
Time: l.Args[2],
Read: l.Args[3] == "1",
Contents: strings.Join(l.Args[4:], " "),
}
account.Memos = append(account.Memos, m)
case "MC": // Create a channel
mlockon, err := strconv.ParseInt(l.Args[4], 16, 0)
if err != nil {
panic(err)
}
c := &Channel{
Name: l.Args[0],
Regtime: l.Args[1],
Seentime: l.Args[2],
Flags: l.Args[3],
MlockOn: int(mlockon),
Metadata: make(map[string]string),
AccessMetadata: make(map[string]AccessMetadata),
}
db.Channels[strings.ToUpper(l.Args[0])] = c
case "CA": // ChanAcs
c, err := db.GetChannel(l.Args[0])
if err != nil {
log.Panicf("Tried to read channel %s but got %#v???", l.Args[0], err)
}
ca := ChanAc{
Channel: l.Args[0],
Account: l.Args[1],
FlagSet: l.Args[2],
DateGranted: l.Args[3],
WhoGranted: l.Args[4],
}
c.Access = append(c.Access, ca)
case "MDC": // Channel metadata
c, err := db.GetChannel(l.Args[0])
if err != nil {
log.Panicf("Tried to read channel %s but got %#v???", l.Args[0], err)
}
c.Metadata[l.Args[1]] = strings.Join(l.Args[2:], " ")
case "MDA": // Channel-based entity key->value
c, err := db.GetChannel(l.Args[0])
if err != nil {
log.Panicf("Tried to read channel %s but got %#v???", l.Args[0], err)
}
amd := AccessMetadata{
ChannelName: l.Args[0],
Entity: l.Args[1],
Key: l.Args[2],
Value: l.Args[3],
}
c.AccessMetadata[strings.ToUpper(amd.Key)] = amd
case "NAM":
nam := &Name{
Name: l.Args[0],
Metadata: make(map[string]string),
}
db.Names[strings.ToUpper(nam.Name)] = nam
case "MDN":
nam, ok := db.Names[strings.ToUpper(l.Args[0])]
if !ok {
panic("Atheme is broken with things")
}
nam.Metadata[l.Args[1]] = strings.Join(l.Args[2:], " ")
case "KID": // Biggest kline id used
kid, err := strconv.ParseInt(l.Args[0], 10, 0)
if err != nil {
panic("atheme is broken with KID " + l.Args[0])
}
db.LastKID = int(kid)
case "XID": // Biggest xline id used
xid, err := strconv.ParseInt(l.Args[0], 10, 0)
if err != nil {
panic("atheme is broken with XID " + l.Args[0])
}
db.LastXID = int(xid)
case "QID": // Biggest qline id used
qid, err := strconv.ParseInt(l.Args[0], 10, 0)
if err != nil {
panic("atheme is broken with QID " + l.Args[0])
}
db.LastQID = int(qid)
case "KL": // kline
id, err := strconv.ParseInt(l.Args[0], 10, 0)
if err != nil {
panic(err)
}
kl := Kline{
ID: int(id),
User: l.Args[1],
Host: l.Args[2],
Duration: l.Args[3],
DateSet: l.Args[4],
WhoSet: l.Args[5],
Reason: strings.Join(l.Args[6:], " "),
}
db.Klines = append(db.Klines, kl)
case "BOT": // BotServ bot
bot := &Bot{
Nick: l.Args[0],
User: l.Args[1],
Host: l.Args[2],
IsPrivate: l.Args[3] == "1",
CreationDate: l.Args[4],
Gecos: l.Args[5],
}
db.Bots[strings.ToUpper(bot.Nick)] = bot
case "BW": // BADWORDS entry
bw := Badword{
Mask: l.Args[0],
TimeSet: l.Args[1],
Setter: l.Args[2],
}
if len(l.Args) == 5 {
bw.Channel = l.Args[3]
bw.Action = l.Args[4]
} else {
bw.Setter = bw.Setter + " " + l.Args[3]
bw.Channel = l.Args[4]
bw.Action = l.Args[5]
}
db.Badwords = append(db.Badwords, bw) // TODO: move this to Channel?
case "GRP": // Group
g := &Group{
UID: l.Args[0],
Name: l.Args[1],
CreationDate: l.Args[2],
Flags: l.Args[3],
Metadata: make(map[string]string),
}
db.Groups[strings.ToUpper(l.Args[1])] = g
case "GACL": // Group access list
g, err := db.GetGroup(l.Args[0])
if err != nil {
log.Panicf("Tried to read group %s but got %#v???", l.Args[0], err)
}
gacl := GroupACL{
GroupName: l.Args[0],
AccountName: l.Args[1],
Flags: l.Args[2],
}
g.ACL = append(g.ACL, gacl)
case "MDG": // Group Metadata
g, err := db.GetGroup(l.Args[0])
if err != nil {
log.Panicf("Tried to read group %s but got %#v???", l.Args[0], err)
}
g.Metadata[l.Args[1]] = strings.Join(l.Args[2:], " ")
case "CLONES-EX": // CLONES exemptions
ce := ClonesExemption{
IP: l.Args[0],
Min: l.Args[1],
Max: l.Args[2],
Expiry: l.Args[3],
Reason: strings.Join(l.Args[4:], " "),
}
db.ClonesExemptions = append(db.ClonesExemptions, ce)
case "LI": // InfoServ INFO posts
ci := ConnectInfo{
Creator: l.Args[0],
Topic: l.Args[1],
CreationDate: l.Args[2],
Body: strings.Join(l.Args[3:], " "),
}
db.ConnectInfos = append(db.ConnectInfos, ci)
case "HO": // Vhost offer
var ho HostOffer
if len(l.Args) == 3 {
ho = HostOffer{
Vhost: l.Args[0],
CreationDate: l.Args[1],
Creator: l.Args[2],
}
} else {
ho = HostOffer{
Group: l.Args[0],
Vhost: l.Args[1],
CreationDate: l.Args[2],
Creator: l.Args[3],
}
}
db.HostOffers = append(db.HostOffers, ho)
case "HR": // Vhost request
hr := HostRequest{
Account: l.Args[0],
Vhost: l.Args[1],
RequestTime: l.Args[2],
}
db.HostRequests = append(db.HostRequests, hr)
// Verbs to ignore
case "":
default:
fmt.Printf("%#v\n", l)
}
}
return
}
func (db *Database) GetAccount(name string) (*Account, error) {
account, ok := db.Accounts[strings.ToUpper(name)]
if !ok {
return nil, NoSuchAcctErr
}
return account, nil
}
func (db *Database) GetChannel(name string) (*Channel, error) {
channel, ok := db.Channels[strings.ToUpper(name)]
if !ok {
return nil, NoSuchChanErr
}
return channel, nil
}
func (db *Database) GetGroup(name string) (*Group, error) {
group, ok := db.Groups[strings.ToUpper(name)]
if !ok {
return nil, NoSuchGroupErr
}
return group, nil
}
func (db *Database) GetBot(name string) (*Bot, error) {
group, ok := db.Bots[strings.ToUpper(name)]
if !ok {
return nil, NoSuchGroupErr
}
return group, nil
}
type Line struct {
Verb string
Args []string
}
type Account struct {
Name string
Email string
Flags string
Kind string
UID string
Password string
Regtime string
LastSeenTime string
Metadata map[string]string
Nicks []GroupedNick
Memos []Memo
CertFP []string
AccessList []Access
Ignores []string
}
type Access struct {
AccountName string
Mask string
}
type Name struct {
Name string
Metadata map[string]string
}
type GroupedNick struct {
Account string
Name string
Regtime string
Seentime string
}
type Memo struct {
Inbox string
From string // an account name
Time string
Read bool
Contents string
}
type Channel struct {
Name string
Regtime string
Seentime string
Flags string
MlockOn int
MlockOff int
MlockLimit int
MlockKey string
Access []ChanAc
Metadata map[string]string
AccessMetadata map[string]AccessMetadata
}
type AccessMetadata struct {
ChannelName string
Entity string
Key string
Value string
}
type ChanAc struct {
Channel string
Account string
FlagSet string
DateGranted string
WhoGranted string
}
type Kline struct {
ID int
User string
Host string
Duration string
DateSet string
WhoSet string
Reason string
}
type Bot struct {
Nick string
User string
Host string
IsPrivate bool
CreationDate string
Gecos string
}
type Badword struct {
Mask string
TimeSet string
Setter string // can be Foo or Foo (Bar)
Channel string
Action string
}
type Group struct {
UID string
Name string
CreationDate string
Flags string
ACL []GroupACL
Metadata map[string]string
}
type GroupACL struct {
GroupName string
AccountName string
Flags string
}
type ConnectInfo struct {
Creator string
Topic string
CreationDate string
Body string
}
type HostOffer struct { // if args number is 3 no group
Group string
Vhost string
CreationDate string
Creator string
}
type HostRequest struct {
Account string
Vhost string
RequestTime string
}
type ClonesExemption struct {
IP string
Min string
Max string
Expiry string
Reason string
}

View File

@ -1,81 +0,0 @@
package main
import (
"flag"
"log"
"strings"
)
var (
leftFname = flag.String("left-db", "./left.db", "database to read from to compare as the left hand")
rightFname = flag.String("right-db", "./right.db", "\" for the right hand side")
)
func main() {
flag.Parse()
leftDB, err := NewDatabase(*leftFname)
if err != nil {
panic(err)
}
_ = leftDB
rightDB, err := NewDatabase(*rightFname)
if err != nil {
panic(err)
}
_ = rightDB
result := &Database{
Accounts: make(map[string]*Account),
Channels: make(map[string]*Channel),
Bots: make(map[string]*Bot),
Groups: make(map[string]*Group),
Names: make(map[string]*Name),
}
_ = result
// Compare accounts and grouped nicks in left database to names in right database
// this is O(scary)
for leftAccountName, acc := range leftDB.Accounts {
for _, leftGroupedNick := range acc.Nicks {
conflictAcc, err := rightDB.GetAccount(leftGroupedNick.Name)
if err != nil {
goto botcheck
}
if conflictAcc.Email == acc.Email {
//log.Printf("Can ignore %s, they are the same user by email account", acc.Name)
goto botcheck
}
log.Printf(
"While trying to see if %s:%s is present in right database, found a conflict with %s",
acc.Name, leftGroupedNick.Name, conflictAcc.Name,
)
log.Printf(
"left: %s %s %s %s",
acc.Name, acc.Email, acc.Regtime, acc.LastSeenTime,
)
log.Printf(
"right: %s %s %s %s",
conflictAcc.Name, conflictAcc.Email, conflictAcc.Regtime, conflictAcc.LastSeenTime,
)
botcheck:
//log.Printf("Checking for bot collisions for %s:%s...", acc.Name, leftGroupedNick.Name)
conflictBot, err := rightDB.GetBot(leftGroupedNick.Name)
if err != nil {
goto next
}
if strings.ToUpper(conflictBot.Nick) == leftAccountName {
log.Printf("Nickname %s conflicts with right's bot %s", leftGroupedNick.Name, conflictBot.Nick)
}
next:
}
}
}

View File

@ -1 +0,0 @@
.env

View File

@ -1,13 +0,0 @@
from "xena/go"
workdir "/"
copy "main.go", "/go/src/github.com/Xe/tools/irc/bncadmin/main.go"
copy "vendor", "/go/src/github.com/Xe/tools/irc/bncadmin/"
run "go install github.com/Xe/tools/irc/bncadmin && cp /go/bin/bncadmin /usr/bin/bncadmin"
run "rm -rf /usr/local/go /go && apk del bash gcc musl-dev openssl go"
flatten
cmd "/usr/bin/bncadmin"
tag "xena/bncadmin"

View File

@ -1,191 +0,0 @@
package main
import (
"crypto/tls"
"fmt"
"log"
"os"
"strings"
"sync"
"time"
"github.com/belak/irc"
_ "github.com/joho/godotenv/autoload"
)
var (
bncUsername = needEnv("BNC_USERNAME")
bncPassword = needEnv("BNC_PASSWORD")
bncServer = needEnv("BNC_SERVER")
serverSuffixExpected = needEnv("SERVER_SUFFIX")
)
func needEnv(key string) string {
v := os.Getenv(key)
if v == "" {
log.Fatal("need value for " + key)
}
return v
}
func main() {
log.Println("Bot connecting to " + bncServer)
conn, err := tls.Dial("tcp", bncServer, &tls.Config{
InsecureSkipVerify: true,
})
if err != nil {
log.Fatal(err)
}
defer conn.Close()
c := irc.NewClient(conn, irc.ClientConfig{
Nick: "admin",
Pass: fmt.Sprintf("%s:%s", bncUsername, bncPassword),
User: "BNCbot",
Name: "BNC admin bot",
Handler: NewBot(),
})
for _, cap := range []string{"userhost-in-names", "multi-prefix", "znc.in/server-time-iso"} {
c.Writef("CAP REQ %s", cap)
}
err = c.Run()
if err != nil {
main()
}
}
type Bot struct {
setupDaemon sync.Once
lookingForUserNetworks bool
// i am sorry
launUsername string
}
func NewBot() *Bot {
return &Bot{}
}
func (b *Bot) Handle(c *irc.Client, m *irc.Message) {
b.setupDaemon.Do(func() {
go func() {
for {
b.lookingForUserNetworks = true
c.Writef("PRIVMSG *status ListAllUserNetworks")
time.Sleep(2 * time.Second) // always sleep 2
b.lookingForUserNetworks = false
time.Sleep(1 * time.Hour)
}
}()
})
// log.Printf("in >> %s", m)
switch m.Command {
case "PRIVMSG":
if m.Prefix.Name == "*status" {
b.HandleStarStatus(c, m)
}
if strings.HasPrefix(m.Prefix.Name, "?") {
b.HandlePartyLineCommand(c, m)
}
if m.Params[0] == "#bnc" {
b.HandleCommand(c, m)
}
case "NOTICE":
if m.Prefix.Name == "*status" {
f := strings.Fields(m.Trailing())
if f[0] == "***" {
log.Println(m.Trailing())
// look up geoip and log here
}
}
}
}
func (b *Bot) HandleStarStatus(c *irc.Client, m *irc.Message) {
if b.lookingForUserNetworks {
if strings.HasPrefix(m.Trailing(), "| ") {
f := strings.Fields(m.Trailing())
switch len(f) {
case 11: // user name line
// 11: []string{"|", "AzureDiamond", "|", "N/A", "|", "0", "|", "|", "|", "|", "|"}
username := f[1]
b.launUsername = username
case 15: // server and nick!user@host line
// 15: []string{"|", "`-", "|", "PonyChat", "|", "0", "|", "Yes", "|", "amethyststar.ponychat.net", "|", "test!test@lypbmzxixk.ponychat.net", "|", "1", "|"}
server := f[9]
network := f[3]
if !strings.HasSuffix(server, serverSuffixExpected) {
log.Printf("%s is using the BNC to connect to unknown server %s, removing permissions", b.launUsername, server)
b.RemoveNetwork(c, b.launUsername, network)
c.Writef("PRIVMSG ?%s :You have violated the terms of the BNC service and your account has been disabled. Please contact PonyChat staff to appeal this.", b.launUsername)
c.Writef("PRIVMSG *blockuser block %s", b.launUsername)
}
}
}
}
}
func (b *Bot) HandlePartyLineCommand(c *irc.Client, m *irc.Message) {
split := strings.Fields(m.Trailing())
username := m.Prefix.Name[1:]
if len(split) == 0 {
return
}
switch strings.ToLower(split[0]) {
case "help":
c.Writef("PRIVMSG ?%s :Commands available:", username)
c.Writef("PRIVMSG ?%s :- ChangeName <new desired \"real name\">", username)
c.Writef("PRIVMSG ?%s : Changes your IRC \"real name\" to a new value instead of the default", username)
c.Writef("PRIVMSG ?%s :- Reconnect", username)
c.Writef("PRIVMSG ?%s : Disconnects from PonyChat and connects to PonyChat again", username)
c.Writef("PRIVMSG ?%s :- Help", username)
c.Writef("PRIVMSG ?%s : Shows this Message", username)
case "changename":
if len(split) < 1 {
c.Writef("NOTICE %s :Usage: ChangeName <new desired \"real name\">")
return
}
gecos := strings.Join(split[1:], " ")
c.Writef("PRIVMSG *controlpanel :Set RealName %s %s", username, gecos)
c.Writef("PRIVMSG ?%s :Please reply %q to confirm changing your \"real name\" to: %s", username, "Reconnect", gecos)
case "reconnect":
c.Writef("PRIVMSG ?%s :Reconnecting...", username)
c.Writef("PRIVMSG *controlpanel Reconnect %s PonyChat", username)
}
}
func (b *Bot) HandleCommand(c *irc.Client, m *irc.Message) {
split := strings.Fields(m.Trailing())
if split[0][0] == ';' {
switch strings.ToLower(split[0][1:]) {
case "request":
c.Write("PRIVMSG #bnc :In order to request a BNC account, please connect to the bouncer server (bnc.ponychat.net, ssl port 6697, allow untrusted certs) with your nickserv username and passsword in the server password field (example: AzureDiamond:hunter2)")
case "help":
c.Write("PRIVMSG #bnc :PonyChat bouncer help is available here: https://ponychat.net/help/bnc/")
case "rules":
c.Write("PRIVMSG #bnc :Terms of the BNC")
c.Write("PRIVMSG #bnc :- Do not use the BNC to evade channel bans")
c.Write("PRIVMSG #bnc :- Do not use the BNC to violate any network rules")
c.Write("PRIVMSG #bnc :- Do not use the BNC to connect to any other IRC network than PonyChat")
}
}
}
func (b *Bot) RemoveNetwork(c *irc.Client, username, network string) {
c.Writef("PRIVMSG *controlpanel :DelNetwork %s %s", username, network)
}

View File

@ -1,11 +0,0 @@
#!/bin/bash
set -e
set -x
box box.rb
docker push xena/bncadmin
hyper rm -f bncadmin ||:
hyper pull xena/bncadmin
hyper run --name bncadmin --restart=always -dit --size s1 --env-file .env xena/bncadmin

View File

@ -1,3 +0,0 @@
fd04337c94f98ab7c2ef34fbeb4e821284775095 github.com/belak/irc
4ed13390c0acd2ff4e371e64d8b97c8954138243 github.com/joho/godotenv
4ed13390c0acd2ff4e371e64d8b97c8954138243 github.com/joho/godotenv/autoload

View File

@ -1 +0,0 @@
.env

View File

@ -1,301 +0,0 @@
package main
import (
"crypto/tls"
"log"
"os"
"strings"
"sync"
"time"
"github.com/Xe/ln"
_ "github.com/joho/godotenv/autoload"
irc "gopkg.in/irc.v1"
)
var (
addr = os.Getenv("SERVER")
password = os.Getenv("PASSWORD")
sclock sync.Mutex
scores map[string]float64
)
func main() {
scores = map[string]float64{}
conn, err := tls.Dial("tcp", addr, &tls.Config{
InsecureSkipVerify: true,
})
if err != nil {
log.Fatal(err)
}
ln.Log(ln.F{
"action": "connected",
"where": addr,
})
cli := irc.NewClient(conn, irc.ClientConfig{
Handler: irc.HandlerFunc(scoreCleveland),
Nick: "Xena",
User: "xena",
Name: "cleveland brown termination bot",
Pass: password,
})
ff := ln.FilterFunc(func(e ln.Event) bool {
if val, ok := e.Data["svclog"]; ok && val.(bool) {
delete(e.Data, "svclog")
line, err := ln.DefaultFormatter.Format(e)
if err != nil {
ln.Fatal(ln.F{"err": err})
}
err = cli.Writef("PRIVMSG #services :%s", string(line))
if err != nil {
log.Fatal(err)
}
}
return true
})
ln.DefaultLogger.Filters = append(ln.DefaultLogger.Filters, ff)
go func() {
for {
time.Sleep(30 * time.Second)
sclock.Lock()
defer sclock.Unlock()
changed := 0
ignored := 0
for key, sc := range scores {
if sc >= notifyThreshold {
ignored++
continue
}
scores[key] = sc / 100
changed++
}
sclock.Unlock()
ln.Log(ln.F{
"action": "nerfed_scores",
"changed": changed,
"ignored": ignored,
})
}
}()
go func() {
for {
time.Sleep(5 * time.Minute)
sclock.Lock()
defer sclock.Unlock()
nsc := map[string]float64{}
halved := 0
rem := 0
for key, score := range scores {
if score > 0.01 {
if score > 3 {
score = score / 2
halved++
}
nsc[key] = score
} else {
rem++
}
}
scores = nsc
ln.Log(ln.F{
"action": "reaped_scores",
"removed": rem,
"halved": halved,
"svclog": true,
})
sclock.Unlock()
}
}()
ln.Log(ln.F{
"action": "accepting_input",
"svclog": true,
})
cli.Run()
}
const (
notifyThreshold = 3
autobanThreshold = 10
)
func scoreCleveland(c *irc.Client, m *irc.Message) {
if m.Trailing() == "!ohshitkillit" && m.Prefix.Host == "ponychat.net" {
ln.Fatal(ln.F{
"action": "emergency_stop",
"user": m.Prefix.String(),
"channel": m.Params[0],
"svclog": true,
})
}
sclock.Lock()
defer sclock.Unlock()
if m.Command != "PRIVMSG" {
return
}
/*
if !strings.HasSuffix(m.Params[0], monitorChan) {
return
}
*/
switch m.Params[0] {
case "#services", "#/dev/syslog":
return
}
switch m.Prefix.Name {
case "Taz", "cadance-syslog", "FromDiscord", "Sonata_Dusk", "CQ_Discord", "Onion":
return
case "Sparkler":
// (Sparkler) lol
// (Sparkler) don't banzor me :(
return
case "Aeyris":
// known shitposter, collison risk :(
return
case "Ryunosuke", "WaterStar":
return
}
sc, ok := scores[m.Prefix.Host]
if !ok {
sc = 0
}
for _, line := range lines {
if strings.Contains(strings.ToLower(m.Trailing()), line) {
sc += 1
ln.Log(ln.F{
"action": "siren_compare",
"channel": m.Params[0],
"user": m.Prefix.String(),
"scoredelta": 1,
"svclog": true,
})
}
}
thisLine := strings.ToLower(m.Trailing())
for _, efnLine := range efknockr {
if strings.Contains(thisLine, strings.ToLower(efnLine)) {
sc += 3
ln.Log(ln.F{
"action": "efknockr_detected",
"score": sc,
"user": m.Prefix.String(),
"channel": m.Params[0],
"delta": 3,
"svclog": true,
})
}
}
scores[m.Prefix.Host] = sc
if sc >= notifyThreshold {
ln.Log(ln.F{
"action": "warn",
"channel": m.Params[0],
"user": m.Prefix.String(),
"score": sc,
"svclog": true,
"ping": "Xena",
})
}
if sc >= autobanThreshold {
c.Writef("PRIVMSG OperServ :AKILL ADD %s spamming | Cleveland show spammer", m.Prefix.Name)
c.Writef("PRIVMSG %s :Sorry for that, he's gone now.", m.Params[0])
ln.Log(ln.F{
"action": "kline_added",
"channel": m.Params[0],
"user": m.Prefix.String(),
"score": sc,
"svclog": true,
})
scores[m.Prefix.Host] = 0
}
}
const showLyrics = `my name is cleveland brown and I am proud to be
right back in my hometown with my new family.
there's old friends and new friends and even a bear.
through good times and bad times it's true love we share.
and so I found a place
where everyone will know
my happy mustache face
this is the cleveland show! haha!`
var lines = []string{
"my name is cleveland brown and I am proud to be",
"my name is cl3v3land brown and i am proud to be",
"right back in my hometown with my new family",
"right back in my hometown with my n3w family",
"there's old friends and new friends and even a bear",
"through good times and bad times it's true love we share.",
"and so I found a place",
"where everyone will know",
"my happy mustache face",
"this is the cleveland show! haha!",
}
var efknockr = []string{
"THIS NETWORK IS FUCKING BLOWJOBS LOL COME TO WORMSEC FOR SOME ICE COLD CHATS",
"0 DAY BANANA BOMBS \"OK\"",
"IRC.WORMSEC.US",
"THE HOTTEST MOST EXCLUSIVE SEC ON THE NET",
"THIS NETWORK IS BLOWJOBS! GET ON SUPERNETS FOR COLD HARD CHATS NOW",
"IRC.SUPERNETS.ORG | PORT 6667/6697 (SSL) | #SUPERBOWL | IPV6 READY",
"▓█▓▓▓▒▒▒▒▒▒▓▓▓▓▓▓▓▓▓▓▄░ ░▄▓▓▓▓▓▓▓▓▓█▓▓▓ IRC.WORMSEC.US | #SUPERBOWL",
"THIS NETWORK IS BLOWJOBS! GET ON SUPERNETS FOR COLD HARD CHATS NOW",
"▄",
"███▓▓▒▒▒▒▒▒▒░░░ ░░░░▒▒▒▓▓▓▓",
"▓█▓▓▓▒▒▒▒▒▒▓▓▓▓▓▓▓▓▓▓▄░ ░▄▓▓▓▓▓▓▓▓▓█▓▓▓",
"▒▓▓▓▓▒▒░░▒█▓▓▓▓▓▓▓▓▓▓█░▒░░▒▓▓▓▓▓▓▓▓▓▓▓█▓▓",
"░▒▓▓▒▒▒▒░░▒▒█▓▓▓▓▓▓▓▓▓█░▒░░░▒▓▓▓▓▓▓▓▓▓▓█▒▓░",
"▒▒▒▒▒▒▒▒▒▒▒░░▀▀▀▀▀▀▀ ░▒░░ ░▒▒▒▀▀▀▀▀▀▒▓▓▓▒",
"THE HOTTEST MOST EXCLUSIVE SEC ON THE NET",
"â–‘â–’â–“â–“â–’â–’â–’â–’â–‘â–‘â–’",
"Techman likes to fuck kids in the ass!!",
"https://discord.gg/3b86TH7",
"| |\\\\",
"/ \\ ||",
"( ,( )=m=D~~~ LOL DONGS",
"/ / | |",
}

View File

@ -1 +0,0 @@
cfg

View File

@ -1,4 +0,0 @@
kcpd
====
A simple relay for multiplexing IRC sessions. Useful for bouncers or proxies.

View File

@ -1,93 +0,0 @@
package main
import (
"crypto/tls"
"errors"
"io"
"net"
kcp "github.com/xtaci/kcp-go"
"github.com/xtaci/smux"
)
// Client opens a TCP listener and forwards traffic to the remote server over KCP.
type Client struct {
cfg *Config
listener net.Listener
}
// ErrBadConfig means the configuration is not correctly defined.
var ErrBadConfig = errors.New("kcpd: bad configuration file")
// NewClient constructs a new client with a given config.
func NewClient(cfg *Config) (*Client, error) {
if cfg.Mode != "client" {
return nil, ErrBadConfig
}
if cfg.ClientServerAddress == "" && cfg.ClientUsername == "" && cfg.ClientPassword == "" && cfg.ClientBindaddr == "" {
return nil, ErrBadConfig
}
return &Client{cfg: cfg}, nil
}
// Dial blockingly connects to the remote server and relays TCP traffic.
func (c *Client) Dial() error {
conn, err := kcp.Dial(c.cfg.ClientServerAddress)
if err != nil {
return err
}
defer conn.Close()
tlsConn := tls.Client(conn, &tls.Config{
InsecureSkipVerify: true, // XXX hack please remove
})
defer tlsConn.Close()
session, err := smux.Client(tlsConn, smux.DefaultConfig())
if err != nil {
return err
}
defer session.Close()
l, err := net.Listen("tcp", c.cfg.ClientBindaddr)
if err != nil {
return err
}
defer l.Close()
c.listener = l
for {
cconn, err := l.Accept()
if err != nil {
break
}
cstream, err := session.OpenStream()
if err != nil {
break
}
go copyConn(cconn, cstream)
}
return nil
}
// Close frees resouces acquired in the client.
func (c *Client) Close() error {
return c.listener.Close()
}
// copyConn copies one connection to another bidirectionally.
func copyConn(left, right net.Conn) error {
defer left.Close()
defer right.Close()
go io.Copy(left, right)
io.Copy(right, left)
return nil
}

View File

@ -1,9 +0,0 @@
// gopreload.go
package main
/*
This file is separate to make it very easy to both add into an application, but
also very easy to remove.
*/
import _ "github.com/Xe/gopreload"

View File

@ -1,13 +0,0 @@
package main
import (
"log"
"github.com/google/gops/agent"
)
func init() {
if err := agent.Listen(nil); err != nil {
log.Fatal(err)
}
}

View File

@ -1,110 +0,0 @@
package main
import (
"flag"
"io/ioutil"
"log"
"os"
"time"
"github.com/caarlos0/env"
_ "github.com/joho/godotenv/autoload"
yaml "gopkg.in/yaml.v1"
)
// Config is the configuration for kcpd
type Config struct {
Mode string `env:"KCPD_MODE,required" envDefault:"server" yaml:"mode"`
// Client mode config
// What IP the client should connect to
ClientServerAddress string `env:"KCPD_SERVER_ADDRESS" yaml:"server"`
// Administrator's NickServ username
ClientUsername string `env:"KCPD_ADMIN_USERNAME" yaml:"admin_username"`
// Administrator's NickServ password
ClientPassword string `env:"KCPD_ADMIN_PASSWORD" yaml:"admin_password"`
// Local bindaddr
ClientBindaddr string `env:"KCPD_CLIENT_BINDADDR" yaml:"client_bind"`
// Server mode config
// What UDP port/address should kcpd bind on?
ServerBindAddr string `env:"KCPD_BIND" yaml:"bind"`
// Atheme URL for Nickserv authentication of the administrator for setting up KCP sessions
ServerAthemeURL string `env:"KCPD_ATHEME_URL" yaml:"atheme_url"`
// URL endpoint for allowing/denying users
ServerAllowListEndpoint string `env:"KCPD_ALLOWLIST_ENDPOINT" yaml:"allow_list_endpoint"`
// local ircd (unsecure) endpoint
ServerLocalIRCd string `env:"KCPD_LOCAL_IRCD" yaml:"local_ircd"`
// WEBIRC password to use for local sockets
ServerWEBIRCPassword string `env:"KCPD_WEBIRC_PASSWORD" yaml:"webirc_password"`
// ServerTLSCert is the TLS cert file
ServerTLSCert string `env:"KCPD_TLS_CERT" yaml:"tls_cert"`
// ServerTLSKey is the TLS key file
ServerTLSKey string `env:"KCPD_TLS_KEY" yaml:"tls_key"`
}
var (
configFname = flag.String("config", "", "configuration file to use (if unset config will be pulled from the environment)")
)
func main() {
flag.Parse()
cfg := &Config{}
if *configFname != "" {
fin, err := os.Open(*configFname)
if err != nil {
log.Fatal(err)
}
defer fin.Close()
data, err := ioutil.ReadAll(fin)
if err != nil {
log.Fatal(err)
}
err = yaml.Unmarshal(data, cfg)
if err != nil {
log.Fatal(err)
}
} else {
err := env.Parse(cfg)
if err != nil {
log.Fatal(err)
}
}
switch cfg.Mode {
case "client":
c, err := NewClient(cfg)
if err != nil {
log.Fatal(err)
}
for {
err = c.Dial()
if err != nil {
log.Println(err)
}
time.Sleep(time.Second)
}
case "server":
s, err := NewServer(cfg)
if err != nil {
log.Fatal(err)
}
err = s.ListenAndServe()
if err != nil {
log.Fatal(err)
}
default:
log.Fatal(ErrBadConfig)
}
}

View File

@ -1,97 +0,0 @@
package main
import (
"crypto/tls"
"fmt"
"log"
"net"
kcp "github.com/xtaci/kcp-go"
"github.com/xtaci/smux"
)
// Server represents the server side of kcpd. It listens on KCP and emits TCP connections from KCP streams.
type Server struct {
cfg *Config
}
// NewServer creates a new Server and validates config.
func NewServer(cfg *Config) (*Server, error) {
if cfg.Mode != "server" {
return nil, ErrBadConfig
}
if cfg.ServerBindAddr == "" && cfg.ServerAthemeURL == "" && cfg.ServerAllowListEndpoint == "" && cfg.ServerLocalIRCd == "" && cfg.ServerWEBIRCPassword == "" && cfg.ServerTLSCert == "" && cfg.ServerTLSKey == "" {
return nil, ErrBadConfig
}
return &Server{cfg: cfg}, nil
}
// ListenAndServe blockingly listens on the UDP port and relays KCP streams to TCP sockets.
func (s *Server) ListenAndServe() error {
l, err := kcp.Listen(s.cfg.ServerBindAddr)
if err != nil {
return err
}
defer l.Close()
log.Printf("listening on KCP: %v", l.Addr())
for {
conn, err := l.Accept()
if err != nil {
log.Println(err)
continue
}
go s.handleConn(conn)
}
}
func (s *Server) handleConn(conn net.Conn) error {
defer conn.Close()
log.Printf("new client: %v", conn.RemoteAddr())
cert, err := tls.LoadX509KeyPair(s.cfg.ServerTLSCert, s.cfg.ServerTLSKey)
if err != nil {
return err
}
tcfg := &tls.Config{
InsecureSkipVerify: true, // XXX hack remove
Certificates: []tls.Certificate{cert},
}
tlsConn := tls.Server(conn, tcfg)
defer tlsConn.Close()
session, err := smux.Server(tlsConn, smux.DefaultConfig())
if err != nil {
return err
}
defer session.Close()
for {
cstream, err := session.AcceptStream()
if err != nil {
log.Printf("client at %s error: %v", conn.RemoteAddr(), err)
return err
}
ircConn, err := net.Dial("tcp", s.cfg.ServerLocalIRCd)
if err != nil {
log.Printf("client at %s error: %v", conn.RemoteAddr(), err)
return err
}
host, _, _ := net.SplitHostPort(conn.RemoteAddr().String())
fmt.Fprintf(ircConn, "WEBIRC %s %s %s %s\r\n", s.cfg.ServerWEBIRCPassword, RandStringRunes(8), host, host)
go copyConn(cstream, ircConn)
}
return nil
}

View File

@ -1,81 +0,0 @@
# Your stdlib service: xena/kcpdwhitelist
This is the README for your service.
A few notes;
`package.json` is NPM-compatible and contains some stdlib configuration details.
`.gitignore` has also been provided for your convenience.
# package.json
This is a standard `package.json`. You'll notice an additional `"stdlib"` field.
You can configure your service for the stdlib registry using;
`name` - The name to register on stdlib, in the format of `<username>/<service>`.
In order to compile to the registry you must have permission to compile to the
provided username's account.
`defaultFunction` - Execute if provided no function route (root service).
If not specified, your base service route will provide a list of available
functions in JSON format.
`timeout` - The time in ms at which to kill service execution. Free accounts are
limited to 30 seconds (30000).
`publish` - Whether to publish releases (versioned) to the stdlib public
directory. Packages pushed to the registry in non-release environments will
never be published.
# env.json
Environment configuration for your service. Each top level key (i.e.
`"dev"` and `"release"`) specifies their own set of key-value
pairs for a specific execution environment. The keys and values specified
are automatically added to the `process.env` variable in Node.js.
`"dev"` is the *non-configurable* name of the local environment, but can
also be used as an environment name for compilation
(i.e. `$ lib up development`).
`"release"` is the *non-configurable* name of the production environment when
you create releases with `$ lib release`.
You can add additional environments and key-value pairs, and use them for
compilation with `lib up <environment>`. Note that free accounts are
restricted to one compilation environment (aside from `"release"`).
*We recommend against checking this file in to version control*. It will be
saved with your tarball and is privately retrievable from the stdlib registry
using your account credentials. It has been added to `.gitignore` by default.
# f/main/function.json
This is your function definition file. The following fields can be used for
execution configuration of specific functions within your service.
`name` - The function name. This maps to an execution route over HTTP. For
example, `xena/kcpdwhitelist/main` would map to the first
function you've created.
`description` - A brief description of the function. To provide detailed
information about function execution, overwrite this README.
`args` - An `Array` describing each argument as you expect them to be passed to
`params.args`.
`kwargs` - An `Object` describing each keyword argument as you expect them to be
passed to `params.kwargs`
`http` - Information to provide to function requests over HTTP.
`http.headers` - HTTP headers to return in the response. Examples are
`"Content-Type"` to specify file type if your function returns a `Buffer` or
`"Access-Control-Allow-Origin"` to restrict browser-based function requests.
# f/main/index.js
The entry point to your function described in `f/main/function.json`.
This is *non-configurable*. You may add as many subdirectories and supportive
files as you like, but `index.js` will remain the entry point and *must*
export a function to be active.

View File

@ -1,8 +0,0 @@
{
"dev": {
"key": "value"
},
"release": {
"key": "value"
}
}

View File

@ -1,15 +0,0 @@
{
"name": "main",
"description": "Function",
"args": [
"First argument",
"Second argument"
],
"kwargs": {
"alpha": "Keyword argument alpha",
"beta": "Keyword argument beta"
},
"http": {
"headers": {}
}
}

View File

@ -1,32 +0,0 @@
/* Import dependencies, declare constants */
win = (callback) => {
callback(null, "allowed");
};
fail = (callback) => {
callback("not allowed");
};
/**
* Your function call
* @param {Object} params Execution parameters
* Members
* - {Array} args Arguments passed to function
* - {Object} kwargs Keyword arguments (key-value pairs) passed to function
* - {String} remoteAddress The IPv4 or IPv6 address of the caller
*
* @param {Function} callback Execute this to end the function call
* Arguments
* - {Error} error The error to show if function fails
* - {Any} returnValue JSON serializable (or Buffer) return value
*/
module.exports = (params, callback) => {
switch (params.kwargs.user) {
case "Xena":
win(callback);
default:
fail(callback);
}
};

View File

@ -1,19 +0,0 @@
{
"name": "kcpdwhitelist",
"version": "0.0.2",
"description": "Service",
"author": "xena <me@christine.website>",
"main": "functions/main/index.js",
"dependencies": {},
"private": true,
"stdlib": {
"name": "xena/kcpdwhitelist",
"defaultFunction": "main",
"timeout": 10000,
"publish": true,
"personalize": {
"keys": [],
"user": []
}
}
}

View File

@ -1,21 +0,0 @@
package main
import (
"math/rand"
"time"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
// RandStringRunes creates a new random string of length n.
func RandStringRunes(n int) string {
b := make([]rune, n)
for i := range b {
b[i] = letterRunes[rand.Intn(len(letterRunes))]
}
return string(b)
}

View File

@ -1,26 +0,0 @@
9474f19b515f52326c7d197d2d097caa7fc7485e github.com/caarlos0/env
4ed13390c0acd2ff4e371e64d8b97c8954138243 github.com/joho/godotenv
4ed13390c0acd2ff4e371e64d8b97c8954138243 github.com/joho/godotenv/autoload
09cded8978dc9e80714c4d85b0322337b0a1e5e0 github.com/klauspost/cpuid
5abf0ee302ccf4834e84f63ff74eca3e8b88e4e2 github.com/klauspost/reedsolomon
ff09b135c25aae272398c51a07235b90a75aa4f0 github.com/pkg/errors
f75e45921594f847a073eb5637b01a8fe5d21e43 github.com/xtaci/kcp-go
a1a5df8f92af764f378f07d6a3dd8eb3f7aa190a github.com/xtaci/smux
459e26527287adbc2adcc5d0d49abff9a5f315a7 golang.org/x/crypto/blowfish
459e26527287adbc2adcc5d0d49abff9a5f315a7 golang.org/x/crypto/cast5
459e26527287adbc2adcc5d0d49abff9a5f315a7 golang.org/x/crypto/pbkdf2
459e26527287adbc2adcc5d0d49abff9a5f315a7 golang.org/x/crypto/salsa20
459e26527287adbc2adcc5d0d49abff9a5f315a7 golang.org/x/crypto/salsa20/salsa
459e26527287adbc2adcc5d0d49abff9a5f315a7 golang.org/x/crypto/tea
459e26527287adbc2adcc5d0d49abff9a5f315a7 golang.org/x/crypto/twofish
459e26527287adbc2adcc5d0d49abff9a5f315a7 golang.org/x/crypto/xtea
ffcf1bedda3b04ebb15a168a59800a73d6dc0f4d golang.org/x/net/bpf
ffcf1bedda3b04ebb15a168a59800a73d6dc0f4d golang.org/x/net/internal/iana
ffcf1bedda3b04ebb15a168a59800a73d6dc0f4d golang.org/x/net/internal/netreflect
ffcf1bedda3b04ebb15a168a59800a73d6dc0f4d golang.org/x/net/ipv4
9f9df34309c04878acc86042b16630b0f696e1de (dirty) gopkg.in/yaml.v1
a00a8beb369cafd88bb7b32f31fc4ff3219c3565 github.com/Xe/gopreload
62f833fc9f6c4d3223bdb37bd0c2f8951bed8596 github.com/google/gops/agent
62f833fc9f6c4d3223bdb37bd0c2f8951bed8596 github.com/google/gops/internal
62f833fc9f6c4d3223bdb37bd0c2f8951bed8596 github.com/google/gops/signal
c2c54e542fb797ad986b31721e1baedf214ca413 github.com/kardianos/osext

View File

@ -1 +0,0 @@
splatbot

View File

@ -1,6 +0,0 @@
FROM golang:1.4.2
ADD . /go/src/github.com/Xe/tools/irc/splatbot
RUN go get github.com/Xe/tools/irc/splatbot/...
CMD splatbot

View File

@ -1,4 +0,0 @@
/*
Command splatbot is a simple IRC bot that lets you see the latest splatoon maps.
*/
package main

View File

@ -1,53 +0,0 @@
package main
import (
"encoding/json"
"io/ioutil"
"log"
"net/http"
"strings"
"github.com/belak/irc"
)
func handlePrivmsg(c *irc.Client, e *irc.Event) {
if strings.HasPrefix(e.Trailing(), "!splatoon") {
splatoonLookup(c, e)
}
}
func splatoonLookup(c *irc.Client, e *irc.Event) {
resp, err := http.Get(url)
if err != nil {
c.Reply(e, "Couldn't look up splatoon maps: %s", err.Error())
return
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
c.Reply(e, "Couldn't look up splatoon maps: %s", err.Error())
return
}
defer resp.Body.Close()
var sd []SplatoonData
err = json.Unmarshal(body, &sd)
if err != nil {
c.Reply(e, "Couldn't look up splatoon maps: %s", err.Error())
return
}
data := sd[0]
stage1 := data.Stages[0]
stage2 := data.Stages[1]
c.Reply(
e,
"From %s to %s, the stage rotation is %s and %s",
data.DatetimeTermBegin, data.DatetimeTermEnd,
englishIfy(stage1), englishIfy(stage2),
)
log.Printf("%s asked me to look up data", e.Identity.Nick)
}

View File

@ -1,45 +0,0 @@
package main
import (
"flag"
"fmt"
"github.com/belak/irc"
)
var (
nick = flag.String("nick", "Inkling", "Nickname to use")
user = flag.String("user", "xena", "Username to use")
channels = flag.String("channels", "#niichan", "Comma-separated list of channels to join")
server = flag.String("server", "irc.ponychat.net", "Server to connect to")
port = flag.Int("port", 6697, "port to connect to")
ssl = flag.Bool("ssl", true, "Use ssl?")
)
func init() {
flag.Parse()
}
func main() {
handler := irc.NewBasicMux()
client := irc.NewClient(irc.HandlerFunc(handler.HandleEvent), *nick, *user, "SplatBot by Xena", "")
handler.Event("001", func(c *irc.Client, e *irc.Event) {
c.Writef("MODE %s +B", c.CurrentNick())
c.Writef("JOIN %s", *channels)
})
handler.Event("PRIVMSG", handlePrivmsg)
var err error
if *ssl {
err = client.DialTLS(fmt.Sprintf("%s:%d", *server, *port), nil)
} else {
err = client.Dial(fmt.Sprintf("%s:%d", *server, *port))
}
if err != nil {
panic(err)
}
}

View File

@ -1,32 +0,0 @@
package main
import "fmt"
const url = "https://s3-ap-northeast-1.amazonaws.com/splatoon-data.nintendo.net/stages_info.json"
var mapNames map[string]string
func init() {
mapNames = map[string]string{
"eefffc33ee1956b7b70e250d5835aa67be9152d42bc76aa8874987ebdfc19944": "Urchin Underpass",
"b8067d2839476ec39072e371b4c59fa85454cdb618515af080ca6080772f3264": "Port Mackerel",
"50c01bca5b3117f4f7893df86d2e2d95435dbb1aae1da6831b8e74838859bc7d": "Saltspray Rig",
"9a1736540c3fde7e409cb9c7e333441157d88dfe8ce92bc6aafcb9f79c56cb3d": "Blackbelly Skatepark",
"d7bf0ca4466e980f994ef7b32faeb71d80611a28c5b9feef84a00e3c4c9d7bc1": "Walleye Warehouse",
"8c69b7c9a81369b5cfd22adbf41c13a8df01969ff3d0e531a8bcb042156bc549": "Arowana Mall",
"1ac0981d03c18576d9517f40461b66a472168a8f14f6a8714142af9805df7b8c": "Bluefin Depot",
"c52a7ab7202a576ee18d94be687d97190e90fdcc25fc4b1591c1a8e0c1c299a5": "Kelp Dome",
"6a6c3a958712adedcceb34f719e220ab0d840d8753e5f51b089d363bd1763c91": "Moray Towers",
"a54716422edf71ac0b3d20fbb4ba5970a7a78ba304fcf935aaf69254d61ca709": "Flounder Heights",
"fafe7416d363c7adc8c5c7b0f76586216ba86dcfe3fd89708d672e99bc822adc": "Camp Triggerfish",
}
}
func englishIfy(s *Stage) string {
name, ok := mapNames[s.ID]
if !ok {
return fmt.Sprintf("Please tell Xena the name of stage id \"%s\" with jpn name %s", s.ID, s.Name)
}
return name
}

View File

@ -1,12 +0,0 @@
package main
type SplatoonData struct {
DatetimeTermBegin string `json:"datetime_term_begin"`
DatetimeTermEnd string `json:"datetime_term_end"`
Stages []*Stage `json:"stages"`
}
type Stage struct {
ID string `json:"id"`
Name string `json:"name"`
}

View File

@ -1,2 +0,0 @@
smartbot
*.gob

View File

@ -1,87 +0,0 @@
package main
import (
"bufio"
"flag"
"log"
"math/rand"
"os"
"time"
"github.com/thoj/go-ircevent"
)
var (
brainInput = flag.String("brain", "", "brain file")
lastSpoken time.Time
)
func main() {
flag.Parse()
chain := NewChain(3)
if *brainInput != "" {
log.Printf("Opening %s...", *brainInput)
fin, err := os.Open(*brainInput)
if err != nil {
panic(err)
}
s := bufio.NewScanner(fin)
for s.Scan() {
t := s.Text()
_, err := chain.Write(t)
if err != nil {
panic(err)
}
}
err = chain.Save("mybrain-pc.gob")
if err != nil {
panic(err)
}
} else {
err := chain.Load("mybrain-pc.gob")
if err != nil {
panic(err)
}
}
rand.Seed(time.Now().Unix())
conn := irc.IRC("BeefSupreme", "Doritos")
err := conn.Connect("irc.ponychat.net:6667")
if err != nil {
panic(err)
}
conn.AddCallback("001", func(e *irc.Event) {
conn.Join("#geek")
})
conn.AddCallback("PRIVMSG", func(e *irc.Event) {
log.Printf("writing brain with %s", e.Arguments[1])
chain.Write(e.Arguments[1])
chain.Save("mybrain-pc.gob")
})
conn.AddCallback("PRIVMSG", func(e *irc.Event) {
if lastSpoken.Add(5 * time.Minute).Before(time.Now()) {
log.Println("It's been long enough that I can speak!")
if rand.Int()%4 == 2 {
log.Printf("About to say something...")
time.Sleep(time.Duration((rand.Int()%15)+4) * time.Second)
conn.Privmsg(e.Arguments[0], chain.Generate(15))
lastSpoken = time.Now()
}
}
})
conn.Loop()
}

View File

@ -1,137 +0,0 @@
package main
// This Markov chain code is taken from the "Generating arbitrary text"
// codewalk: http://golang.org/doc/codewalk/markov/
//
// Minor modifications have been made to make it easier to integrate
// with a webserver and to save/load state
import (
"encoding/gob"
"fmt"
"math/rand"
"os"
"strings"
"sync"
)
// Prefix is a Markov chain prefix of one or more words.
type Prefix []string
// String returns the Prefix as a string (for use as a map key).
func (p Prefix) String() string {
return strings.Join(p, " ")
}
// Shift removes the first word from the Prefix and appends the given word.
func (p Prefix) Shift(word string) {
copy(p, p[1:])
p[len(p)-1] = word
}
// Chain contains a map ("chain") of prefixes to a list of suffixes.
// A prefix is a string of prefixLen words joined with spaces.
// A suffix is a single word. A prefix can have multiple suffixes.
type Chain struct {
Chain map[string][]string
prefixLen int
mu sync.Mutex
}
// NewChain returns a new Chain with prefixes of prefixLen words.
func NewChain(prefixLen int) *Chain {
return &Chain{
Chain: make(map[string][]string),
prefixLen: prefixLen,
}
}
// Write parses the bytes into prefixes and suffixes that are stored in Chain.
func (c *Chain) Write(in string) (int, error) {
sr := strings.NewReader(in)
p := make(Prefix, c.prefixLen)
for {
var s string
if _, err := fmt.Fscan(sr, &s); err != nil {
break
}
key := p.String()
c.mu.Lock()
c.Chain[key] = append(c.Chain[key], s)
c.mu.Unlock()
p.Shift(s)
}
return len(in), nil
}
// Generate returns a string of at most n words generated from Chain.
func (c *Chain) Generate(n int) string {
c.mu.Lock()
defer c.mu.Unlock()
p := make(Prefix, c.prefixLen)
var words []string
for i := 0; i < n; i++ {
choices := c.Chain[p.String()]
if len(choices) == 0 {
break
}
next := choices[rand.Intn(len(choices))]
words = append(words, next)
p.Shift(next)
}
return strings.Join(words, " ")
}
// Save the chain to a file
func (c *Chain) Save(fileName string) error {
// Open the file for writing
fo, err := os.Create(fileName)
if err != nil {
return err
}
// close fo on exit and check for its returned error
defer func() {
if err := fo.Close(); err != nil {
panic(err)
}
}()
// Create an encoder and dump to it
c.mu.Lock()
defer c.mu.Unlock()
enc := gob.NewEncoder(fo)
err = enc.Encode(c)
if err != nil {
return err
}
return nil
}
// Load the chain from a file
func (c *Chain) Load(fileName string) error {
// Open the file for reading
fi, err := os.Open(fileName)
if err != nil {
return err
}
// close fi on exit and check for its returned error
defer func() {
if err := fi.Close(); err != nil {
panic(err)
}
}()
// Create a decoder and read from it
c.mu.Lock()
defer c.mu.Unlock()
dec := gob.NewDecoder(fi)
err = dec.Decode(c)
if err != nil {
return err
}
return nil
}

View File

@ -1,2 +0,0 @@
almarid
.env

View File

@ -1,13 +0,0 @@
package main
import (
"log"
"github.com/google/gops/agent"
)
func init() {
if err := agent.Listen(nil); err != nil {
log.Fatal(err)
}
}

View File

@ -1,109 +0,0 @@
package main
import (
"bytes"
"crypto/rand"
"fmt"
"io/ioutil"
"math/big"
"os"
"strings"
"time"
"github.com/McKael/madon"
"github.com/Xe/ln"
"github.com/caarlos0/env"
_ "github.com/joho/godotenv/autoload"
)
var cfg = &struct {
Instance string `env:"INSTANCE,required"`
AppID string `env:"APP_ID,required"`
AppSecret string `env:"APP_SECRET,required"`
Token string `env:"TOKEN,required"`
WordFile string `env:"WORD_FILE,required"`
}{}
func main() {
err := env.Parse(cfg)
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "env.Parse"})
}
fin, err := os.Open(cfg.WordFile)
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "os.Open(cfg.WordFile)"})
}
data, err := ioutil.ReadAll(fin)
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "ioutil.ReadAll(fin)"})
}
c, err := madon.RestoreApp("almarid:", cfg.Instance, cfg.AppID, cfg.AppSecret, &madon.UserToken{AccessToken: cfg.Token})
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "madon.RestoreApp"})
}
_ = c
lines := bytes.Split(data, []byte("\n"))
words := []string{}
for _, line := range lines {
if len(line) > 5 {
word := string(line)
if strings.HasPrefix(word, "'") {
word = word[1:]
}
words = append(words, word)
}
}
ln.Log(ln.F{"action": "words.loaded", "count": len(words)})
lenBig := big.NewInt(int64(len(words)))
first := true
for {
bi, err := rand.Int(rand.Reader, lenBig)
if err != nil {
ln.Log(ln.F{
"action": "big.Rand",
"err": err,
})
continue
}
i := int(bi.Int64())
if first {
first = false
} else {
time.Sleep(5 * time.Minute)
}
txt := fmt.Sprintf("%s is not doing, allah is doing", words[i])
st, err := c.PostStatus(txt, 0, nil, false, "", "public")
if err != nil {
ln.Log(ln.F{
"err": err,
"action": "c.PostStatus",
"text": txt,
})
continue
}
ln.Log(ln.F{
"action": "tooted",
"text": txt,
"id": st.ID,
"url": st.URL,
})
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,2 +0,0 @@
.env
furrybb

View File

@ -1,37 +0,0 @@
furrybb
======
This boosts any toots with the tag `#furry`, but this can be used for other
hashtags too. Usage is simple:
```console
$ go get github.com/Xe/x/mastodon/furrybb
$ cd $GOPATH/src/github.com/Xe/x/mastodon/furrybb
$ go get github.com/Xe/x/mastodon/mkapp
$ mkapp
Usage of [mkapp]:
-app-name string
app name for mastodon (default "Xe/x bot")
-instance string
mastodon instance
-password string
password to generate token
-redirect-uri string
redirect URI for app users (default "urn:ietf:wg:oauth:2.0:oob")
-username string
username to generate token
-website string
website for users that click the app name (default "https://github.com/Xe/x")
exit status 2
$ mkapp [your options here] > .env
$ echo "HASHTAG=furry" >> .env
$ go build && ./furrybb
```
once you see:
```
time="2017-04-22T19:25:28-07:00" action=streaming.toots
```
you're all good fam.

View File

@ -1,9 +0,0 @@
// gopreload.go
package main
/*
This file is separate to make it very easy to both add into an application, but
also very easy to remove.
*/
import _ "github.com/Xe/gopreload"

View File

@ -1,13 +0,0 @@
package main
import (
"log"
"github.com/google/gops/agent"
)
func init() {
if err := agent.Listen(nil); err != nil {
log.Fatal(err)
}
}

View File

@ -1,74 +0,0 @@
package main
import (
"github.com/McKael/madon"
"github.com/Xe/ln"
"github.com/caarlos0/env"
_ "github.com/joho/godotenv/autoload"
)
var cfg = &struct {
Instance string `env:"INSTANCE,required"`
AppID string `env:"APP_ID,required"`
AppSecret string `env:"APP_SECRET,required"`
Token string `env:"TOKEN,required"`
Hashtag string `env:"HASHTAG,required"`
}{}
var scopes = []string{"read", "write", "follow"}
func main() {
err := env.Parse(cfg)
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "startup"})
}
c, err := madon.RestoreApp("furry boostbot", cfg.Instance, cfg.AppID, cfg.AppSecret, &madon.UserToken{AccessToken: cfg.Token})
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "madon.RestoreApp"})
}
evChan := make(chan madon.StreamEvent, 10)
stop := make(chan bool)
done := make(chan bool)
err = c.StreamListener("public", "", evChan, stop, done)
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "c.StreamListener"})
}
ln.Log(ln.F{
"action": "streaming.toots",
})
for {
select {
case _, ok := <-done:
if !ok {
ln.Fatal(ln.F{"action": "stream.dead"})
}
case ev := <-evChan:
switch ev.Event {
case "error":
ln.Fatal(ln.F{"err": ev.Error, "action": "processing.event"})
case "update":
s := ev.Data.(madon.Status)
for _, tag := range s.Tags {
if tag.Name == cfg.Hashtag {
err = c.ReblogStatus(s.ID)
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "c.ReblogStatus", "id": s.ID})
}
ln.Log(ln.F{
"action": "reblogged",
"id": s.ID,
})
}
}
}
}
}
}

View File

@ -1,13 +0,0 @@
039943f9c38eb1f43c26e1ffd21ad691efc00657 github.com/McKael/madon
f759b797c0ff6b2c514202198fe5e8ba90094c14 github.com/Xe/ln
9474f19b515f52326c7d197d2d097caa7fc7485e github.com/caarlos0/env
e8f0f8aaa98dfb6586cbdf2978d511e3199a960a github.com/gorilla/websocket
726cc8b906e3d31c70a9671c90a13716a8d3f50d github.com/joho/godotenv
726cc8b906e3d31c70a9671c90a13716a8d3f50d github.com/joho/godotenv/autoload
248dadf4e9068a0b3e79f02ed0a610d935de5302 github.com/pkg/errors
14de1ac72d9ae5c3c0d7c02164c52ebd3b951a4e github.com/sendgrid/rest
a00a8beb369cafd88bb7b32f31fc4ff3219c3565 github.com/Xe/gopreload
62f833fc9f6c4d3223bdb37bd0c2f8951bed8596 github.com/google/gops/agent
62f833fc9f6c4d3223bdb37bd0c2f8951bed8596 github.com/google/gops/internal
62f833fc9f6c4d3223bdb37bd0c2f8951bed8596 github.com/google/gops/signal
c2c54e542fb797ad986b31721e1baedf214ca413 github.com/kardianos/osext

View File

@ -1,36 +0,0 @@
package main
import (
"flag"
"fmt"
"log"
"github.com/McKael/madon"
)
var (
instance = flag.String("instance", "", "mastodon instance")
appName = flag.String("app-name", "Xe/x bot", "app name for mastodon")
redirectURI = flag.String("redirect-uri", "urn:ietf:wg:oauth:2.0:oob", "redirect URI for app users")
website = flag.String("website", "https://github.com/Xe/x", "website for users that click the app name")
username = flag.String("username", "", "username to generate token")
password = flag.String("password", "", "password to generate token")
)
var scopes = []string{"read", "write", "follow"}
func main() {
flag.Parse()
c, err := madon.NewApp(*appName, scopes, *redirectURI, *instance)
if err != nil {
log.Fatal(err)
}
err = c.LoginBasic(*username, *password, scopes)
if err != nil {
log.Fatal(err)
}
fmt.Printf("APP_ID=%s\nAPP_SECRET=%s\nTOKEN=%s\nINSTANCE=%s", c.ID, c.Secret, c.UserToken.AccessToken, *instance)
}

View File

@ -1,53 +0,0 @@
package commands
import (
"math/rand"
"strings"
"time"
"github.com/justinian/dice"
"github.com/syfaro/finch"
"gopkg.in/telegram-bot-api.v4"
)
func init() {
finch.RegisterCommand(&diceCommand{})
rand.Seed(time.Now().Unix())
}
type diceCommand struct {
finch.CommandBase
}
func (cmd *diceCommand) Help() finch.Help {
return finch.Help{
Name: "Dice",
Description: "Standard: xdy[[k|d][h|l]z][+/-c] - rolls and sums x y-sided dice, keeping or dropping the lowest or highest z dice and optionally adding or subtracting c.",
Example: "/dice@@ 4d6kh3+4",
Botfather: [][]string{
[]string{"dice", "4d20, etc"},
},
}
}
func (cmd *diceCommand) ShouldExecute(message tgbotapi.Message) bool {
return finch.SimpleCommand("dice", message.Text)
}
func (cmd *diceCommand) Execute(message tgbotapi.Message) error {
parv := strings.Fields(message.CommandArguments())
if len(parv) != 1 {
msg := tgbotapi.NewMessage(message.Chat.ID, "Try something like 4d20")
return cmd.Finch.SendMessage(msg)
}
text, _, err := dice.Roll(parv[0])
if err != nil {
return err
}
msg := tgbotapi.NewMessage(message.Chat.ID, text.String())
return cmd.Finch.SendMessage(msg)
}

View File

@ -1,58 +0,0 @@
package commands
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"github.com/syfaro/finch"
"gopkg.in/telegram-bot-api.v4"
)
func init() {
finch.RegisterCommand(&printerfactCommand{})
}
type printerfactCommand struct {
finch.CommandBase
}
func (cmd *printerfactCommand) Help() finch.Help {
return finch.Help{
Name: "Printerfact",
Description: "Displays printerfactrmation about the currently requesting user",
Example: "/printerfact@@",
Botfather: [][]string{
[]string{"printerfact", "Printerfactrmation about the current user"},
},
}
}
func (cmd *printerfactCommand) ShouldExecute(message tgbotapi.Message) bool {
return finch.SimpleCommand("printerfact", message.Text)
}
func (cmd *printerfactCommand) Execute(message tgbotapi.Message) error {
resp, err := http.Get("http://xena.stdlib.com/printerfacts")
if err != nil {
panic(err)
}
factStruct := &struct {
Facts []string `json:"facts"`
}{}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
json.Unmarshal(body, factStruct)
text := fmt.Sprintf("%s", factStruct.Facts[0])
msg := tgbotapi.NewMessage(message.Chat.ID, text)
return cmd.Finch.SendMessage(msg)
}

View File

@ -1,104 +0,0 @@
package commands
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"time"
"github.com/syfaro/finch"
"gopkg.in/telegram-bot-api.v4"
)
func init() {
finch.RegisterCommand(&splattusCommand{})
}
type splattusCommand struct {
finch.CommandBase
}
func (cmd *splattusCommand) Help() finch.Help {
return finch.Help{
Name: "Splattus",
Description: "Displays splatoon 2 status",
Example: "/splattus@@",
Botfather: [][]string{
[]string{"splattus", "Splatoon 2 map rotations"},
},
}
}
func (cmd *splattusCommand) ShouldExecute(message tgbotapi.Message) bool {
return finch.SimpleCommand("splattus", message.Text)
}
func (cmd *splattusCommand) Execute(message tgbotapi.Message) error {
resp, err := http.Get("https://splatoon.ink/schedule2")
if err != nil {
panic(err)
}
st := &splattus{}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
json.Unmarshal(body, st)
modeInfo := []string{st.Modes.Regular[1].String(), st.Modes.Gachi[1].String(), st.Modes.League[1].String()}
text := strings.Join(modeInfo, "\n")
msg := tgbotapi.NewMessage(message.Chat.ID, text)
return cmd.Finch.SendMessage(msg)
}
type splatoonMode struct {
StartTime int64 `json:"startTime"`
EndTime int64 `json:"endTime"`
Maps []string `json:"maps"`
Rule splatoonRule `json:"rule"`
Mode splatoonGameMode `json:"mode"`
}
func (sm splatoonMode) String() string {
maps := strings.Join(sm.Maps, ", ")
end := time.Unix(sm.EndTime, 0)
now := time.Now()
diff := end.Sub(now)
return fmt.Sprintf("%s:\nRotation ends at %s (in %s)\nMaps: %s\nRule: %s\n", sm.Mode, end.Format(time.RFC3339), diff, maps, sm.Rule)
}
type splatoonGameMode struct {
Key string `json:"key"`
Name string `json:"name"`
}
func (sgm splatoonGameMode) String() string {
return sgm.Name
}
type splatoonRule struct {
Key string `json:"key"`
MultilineName string `json:"multiline_name"`
Name string `json:"name"`
}
func (sr splatoonRule) String() string {
return sr.Name
}
type splattus struct {
UpdateTime int64 `json:"updateTime"`
Modes struct {
League []splatoonMode `json:"league"`
Regular []splatoonMode `json:"regular"`
Gachi []splatoonMode `json:"gachi"`
} `json:"modes"`
}

View File

@ -1,17 +0,0 @@
package main
import (
"os"
_ "github.com/Xe/x/tg/covfefe/commands"
_ "github.com/joho/godotenv/autoload"
"github.com/syfaro/finch"
_ "github.com/syfaro/finch/commands/help"
_ "github.com/syfaro/finch/commands/info"
)
func main() {
f := finch.NewFinch(os.Getenv("TELEGRAM_TOKEN"))
f.Start()
}

View File

@ -1,10 +0,0 @@
a9c833d2837d3b16888d55d5aafa9ffe9afb22b0 github.com/certifi/gocertifi
d175f85701dfbf44cb0510114c9943e665e60907 github.com/getsentry/raven-go
726cc8b906e3d31c70a9671c90a13716a8d3f50d github.com/joho/godotenv
726cc8b906e3d31c70a9671c90a13716a8d3f50d github.com/joho/godotenv/autoload
3d2cfac89f5f4023604c963214759ea5f5d33972 github.com/justinian/dice
1fa76025c307b26485b59eaa8bdfb4866cbee29f github.com/syfaro/finch
1fa76025c307b26485b59eaa8bdfb4866cbee29f github.com/syfaro/finch/commands/help
1fa76025c307b26485b59eaa8bdfb4866cbee29f github.com/syfaro/finch/commands/info
a90a01d73ae432e2611d178c18367fbaa13e0154 github.com/technoweenie/multipartstreamer
0a57807db79efce7f6719fbb2c0e0f83fda79aec gopkg.in/telegram-bot-api.v4

View File

@ -1,2 +0,0 @@
.env
meirl

View File

@ -1,9 +0,0 @@
// gopreload.go
package main
/*
This file is separate to make it very easy to both add into an application, but
also very easy to remove.
*/
import _ "github.com/Xe/gopreload"

View File

@ -1,13 +0,0 @@
package main
import (
"log"
"github.com/google/gops/agent"
)
func init() {
if err := agent.Listen(nil); err != nil {
log.Fatal(err)
}
}

View File

@ -1,110 +0,0 @@
package main
import (
"fmt"
"log"
"os"
"runtime"
"time"
"github.com/McKael/madon"
"github.com/Xe/ln"
"github.com/caarlos0/env"
_ "github.com/joho/godotenv/autoload"
"github.com/turnage/graw"
"github.com/turnage/graw/reddit"
"gopkg.in/telegram-bot-api.v4"
)
const appid = "github.com/Xe/x/tg/meirl"
const version = "0.1-dev"
type config struct {
RedditBotAdmin string `env:"REDDIT_ADMIN_USERNAME,required"`
Subreddits []string `env:"SUBREDDITS,required"`
TelegramToken string `env:"TELEGRAM_TOKEN,required"`
TelegramAdmin string `env:"TELEGRAM_ADMIN,required"`
TelegramChannelID int64 `env:"TELEGRAM_CHANNEL_ID,required"`
MastodonToken string `env:"MASTODON_TOKEN,required"`
MastodonClientSecret string `env:"MASTODON_CLIENT_SECRET,required"`
MastodonClientID string `env:"MASTODON_CLIENT_ID,required"`
MastodonInstance string `env:"MASTODON_INSTANCE,required"`
}
func main() {
var cfg config
err := env.Parse(&cfg)
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "env.Parse"})
}
tg, err := tgbotapi.NewBotAPI(cfg.TelegramToken)
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "tgbotapi.NewBotAPI"})
}
ln.Log(ln.F{"action": "telegram_active", "username": tg.Self.UserName})
userAgent := fmt.Sprintf(
"%s on %s %s:%s:%s (by /u/%s)",
runtime.Version(), runtime.GOOS, runtime.GOARCH,
appid, version, cfg.RedditBotAdmin,
)
rd, err := reddit.NewScript(userAgent, 5*time.Second)
if err != nil {
ln.Fatal(ln.F{"err": err, "user_agent": userAgent})
}
_ = rd
ln.Log(ln.F{"action": "reddit_connected", "user_agent": userAgent})
md, err := madon.RestoreApp("me_irl", cfg.MastodonInstance, cfg.MastodonClientID, cfg.MastodonClientSecret, &madon.UserToken{AccessToken: cfg.MastodonToken})
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "madon.RestoreApp"})
}
a := &announcer{
cfg: &cfg,
tg: tg,
md: md,
}
stop, wait, err := graw.Scan(a, rd, graw.Config{Subreddits: cfg.Subreddits, Logger: log.New(os.Stderr, "", log.LstdFlags)})
if err != nil {
ln.Fatal(ln.F{"err": err, "action": "graw.Scan", "subreddits": cfg.Subreddits})
}
defer stop()
// This time, let's block so the bot will announce (ideally) forever.
if err := wait(); err != nil {
ln.Fatal(ln.F{"err": err, "action": "reddit_wait"})
}
}
type announcer struct {
cfg *config
tg *tgbotapi.BotAPI
md *madon.Client
}
func (a *announcer) Post(post *reddit.Post) error {
txt := fmt.Sprintf("me irl\n%s\n(https://reddit.com%s by /u/%s)", post.URL, post.Permalink, post.Author)
msg := tgbotapi.NewMessage(a.cfg.TelegramChannelID, txt)
tmsg, err := a.tg.Send(msg)
if err != nil {
return err
}
toot, err := a.md.PostStatus(txt, 0, nil, false, "", "public")
if err != nil {
return err
}
ln.Log(ln.F{"action": "new_post", "url": post.URL, "permalink": post.Permalink, "redditor": post.Author, "toot_id": toot.ID, "tg_id": tmsg.MessageID})
return nil
}

View File

@ -1,139 +0,0 @@
package main
import (
"fmt"
"image"
"log"
"net/http"
"os"
"runtime"
"time"
"github.com/Xe/uuid"
"github.com/fogleman/primitive/primitive"
_ "github.com/joho/godotenv/autoload"
"gopkg.in/telegram-bot-api.v4"
// image formats
_ "image/jpeg"
_ "image/png"
_ "github.com/hullerob/go.farbfeld"
_ "golang.org/x/image/bmp"
_ "golang.org/x/image/tiff"
_ "golang.org/x/image/webp"
)
func main() {
bot, err := tgbotapi.NewBotAPI(os.Getenv("TELEGRAM_TOKEN"))
if err != nil {
log.Panic(err)
}
ps, ok := puushLogin(os.Getenv("PUUSH_KEY"))
if !ok {
log.Fatal("puush login failed")
}
u := tgbotapi.NewUpdate(0)
u.Timeout = 60
updates, err := bot.GetUpdatesChan(u)
for update := range updates {
if update.Message == nil {
continue
}
err := renderImg(bot, ps, update)
if err != nil {
msg := tgbotapi.NewMessage(update.Message.Chat.ID, "error: "+err.Error())
log.Printf("error in processing message from %s: %v", update.Message.From.String(), err)
bot.Send(msg)
}
}
}
func stepImg(img image.Image, count int) image.Image {
bg := primitive.MakeColor(primitive.AverageImageColor(img))
model := primitive.NewModel(img, bg, 512, runtime.NumCPU())
for range make([]struct{}, count) {
model.Step(primitive.ShapeTypeTriangle, 128, 0)
}
return model.Context.Image()
}
func renderImg(bot *tgbotapi.BotAPI, ps string, update tgbotapi.Update) error {
msg := update.Message
// ignore chats without photos
if len(*msg.Photo) == 0 {
return nil
}
p := *msg.Photo
pho := p[len(p)-1]
fu, err := bot.GetFileDirectURL(pho.FileID)
if err != nil {
return err
}
resp, err := http.Get(fu)
if err != nil {
return err
}
defer resp.Body.Close()
img, ifmt, err := image.Decode(resp.Body)
if err != nil {
return err
}
log.Printf("%s: image id %s loaded (%s)", msg.From, pho.FileID, ifmt)
umsg := tgbotapi.NewMessage(update.Message.Chat.ID, "rendering... (may take a while)")
bot.Send(umsg)
before := time.Now()
imgs := []image.Image{}
for i := range make([]struct{}, 10) {
log.Printf("%s: starting frame render", msg.From)
imgs = append(imgs, stepImg(img, 150))
log.Printf("%s: frame rendered", msg.From)
umsg = tgbotapi.NewMessage(update.Message.Chat.ID, fmt.Sprintf("frame %d/10 rendered", i+1))
bot.Send(umsg)
}
gpath := "./var/" + update.Message.From.String() + ".gif"
err = primitive.SaveGIFImageMagick(gpath, imgs, 15, 15)
if err != nil {
return err
}
after := time.Now().Sub(before)
buf, err := os.Open(gpath)
if err != nil {
return err
}
defer os.Remove(gpath)
umsg = tgbotapi.NewMessage(update.Message.Chat.ID, "uploading (took "+after.String()+" to render)")
bot.Send(umsg)
furl, err := puush(ps, uuid.New()+".gif", buf)
if err != nil {
return err
}
omsg := tgbotapi.NewMessage(update.Message.Chat.ID, furl.String())
_, err = bot.Send(omsg)
if err != nil {
return err
}
return nil
}

View File

@ -1,93 +0,0 @@
package main
import (
"bytes"
"crypto/md5"
"errors"
"fmt"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"net/url"
"strings"
)
// Puush constants
const (
PuushBase = "https://puush.me/api/"
PuushAuthURL = "https://puush.me/api/auth/"
PuushUploadURL = "https://puush.me/api/up/"
)
func puushLogin(key string) (string, bool) {
r, err := http.PostForm(PuushAuthURL, url.Values{"k": {key}})
if err != nil {
fmt.Println(err)
return "", false
}
body, _ := ioutil.ReadAll(r.Body)
r.Body.Close()
info := strings.Split(string(body), ",")
if info[0] == "-1" {
return "", false
}
session := info[1]
return session, true
}
func puush(session, fname string, fin io.Reader) (*url.URL, error) {
buf := new(bytes.Buffer)
w := multipart.NewWriter(buf)
kwriter, err := w.CreateFormField("k")
if err != nil {
return nil, err
}
io.WriteString(kwriter, session)
file, _ := ioutil.ReadAll(fin)
h := md5.New()
h.Write(file)
cwriter, err := w.CreateFormField("c")
if err != nil {
return nil, err
}
io.WriteString(cwriter, fmt.Sprintf("%x", h.Sum(nil)))
zwriter, err := w.CreateFormField("z")
if err != nil {
return nil, err
}
io.WriteString(zwriter, "poop") // They must think their protocol is shit
fwriter, err := w.CreateFormFile("f", fname)
if err != nil {
return nil, err
}
fwriter.Write(file)
w.Close()
req, err := http.NewRequest("POST", "http://puush.me/api/up", buf)
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", w.FormDataContentType())
client := &http.Client{}
res, err := client.Do(req)
if err != nil {
return nil, err
}
body, _ := ioutil.ReadAll(res.Body)
res.Body.Close()
info := strings.Split(string(body), ",")
if info[0] == "0" {
return url.Parse(info[1])
}
return nil, errors.New("upload failed")
}

View File

@ -1,22 +0,0 @@
62b230097e9c9534ca2074782b25d738c4b68964 (dirty) github.com/Xe/uuid
ee8994ff90057955c428a5a949da5d064bf3ce6b github.com/fogleman/gg
80f39ceaa8f4c66acb28aba6abe6b15128c06113 github.com/fogleman/primitive/primitive
bcfeb16b74e8aea9e2fe043406f2ef74b1cb0759 github.com/golang/freetype/raster
bcfeb16b74e8aea9e2fe043406f2ef74b1cb0759 github.com/golang/freetype/truetype
b572f0728b691aae4256edb2e408279146eafe52 github.com/hullerob/go.farbfeld
325433c502d409f3c3dc820098fb0cfe38d98dc7 github.com/joho/godotenv
325433c502d409f3c3dc820098fb0cfe38d98dc7 github.com/joho/godotenv/autoload
a90a01d73ae432e2611d178c18367fbaa13e0154 github.com/technoweenie/multipartstreamer
426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/bmp
426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/draw
426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/font
426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/font/basicfont
426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/math/f64
426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/math/fixed
426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/riff
426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/tiff
426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/tiff/lzw
426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/vp8
426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/vp8l
426cfd8eeb6e08ab1932954e09e3c2cb2bc6e36d golang.org/x/image/webp
0a57807db79efce7f6719fbb2c0e0f83fda79aec (dirty) gopkg.in/telegram-bot-api.v4

View File

@ -1 +0,0 @@
atheme

View File

@ -1,95 +0,0 @@
package main
import (
"bufio"
"flag"
"fmt"
"log"
"os"
"github.com/Xe/Tetra/atheme"
"github.com/howeyc/gopass"
)
var (
client *atheme.Atheme
serverString = flag.String("server", "http://127.0.0.1:8080/xmlrpc", "what http://server:port to connect to")
cookie = flag.String("cookie", "", "authentication cookie to use")
user = flag.String("user", "", "username to use")
)
func main() {
flag.Parse()
command := flag.Arg(0)
if command == "" {
flag.Usage()
os.Exit(1)
}
var rest []string
if n := flag.NArg(); n > 1 {
rest = flag.Args()[1:]
}
_ = rest
var err error
client, err = atheme.NewAtheme(*serverString)
if err != nil {
log.Fatal(err)
}
switch command {
case "login":
var username string
var password string
scanner := bufio.NewScanner(os.Stdin)
fmt.Print("Username: ")
for {
scanner.Scan()
username = scanner.Text()
if scanner.Err() == nil {
break
}
fmt.Print("Username: ")
}
fmt.Print("Password: ")
for {
password = string(gopass.GetPasswdMasked())
if password != "" {
break
}
fmt.Print("Password: ")
}
err = client.Login(username, password)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Authcookie: %s\n", client.Authcookie)
case "command":
if *cookie == "" {
log.Fatal("specify cookie")
}
client.Authcookie = *cookie
client.Account = *user
output, err := client.Command(rest...)
if err != nil {
log.Fatal(err)
}
fmt.Println(output)
}
}

View File

@ -1 +0,0 @@
dbupload

View File

@ -1,49 +0,0 @@
package main
type UploadImage struct {
Image struct {
SourceURL string `json:"source_url"`
Tags string `json:"tag_list"`
ImageURL string `json:"image_url"`
} `json:"image"`
}
type Image struct {
ID string `json:"id"`
IDNumber int `json:"id_number"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
DuplicateReports []interface{} `json:"duplicate_reports"`
FileName string `json:"file_name"`
Description string `json:"description"`
Uploader string `json:"uploader"`
Image string `json:"image"`
Score int `json:"score"`
Upvotes int `json:"upvotes"`
Downvotes int `json:"downvotes"`
Faves int `json:"faves"`
CommentCount int `json:"comment_count"`
Tags string `json:"tags"`
TagIds []string `json:"tag_ids"`
Width int `json:"width"`
Height int `json:"height"`
AspectRatio float64 `json:"aspect_ratio"`
OriginalFormat string `json:"original_format"`
MimeType string `json:"mime_type"`
Sha512Hash string `json:"sha512_hash"`
OrigSha512Hash string `json:"orig_sha512_hash"`
SourceURL string `json:"source_url"`
License string `json:"license"`
Representations struct {
ThumbTiny string `json:"thumb_tiny"`
ThumbSmall string `json:"thumb_small"`
Thumb string `json:"thumb"`
Small string `json:"small"`
Medium string `json:"medium"`
Large string `json:"large"`
Tall string `json:"tall"`
Full string `json:"full"`
} `json:"representations"`
IsRendered bool `json:"is_rendered"`
IsOptimized bool `json:"is_optimized"`
}

View File

@ -1 +0,0 @@
dbmanifestgen

View File

@ -1 +0,0 @@
../db.go

View File

@ -1,62 +0,0 @@
package main
import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
)
var (
serverloc = flag.String("serverloc", "http://static.xeserv.us/", "server to prepend to url paths")
sourceloc = flag.String("sourceloc", "", "source URL for metadata generation")
set = flag.String("set", "", "comic set")
)
func main() {
flag.Parse()
if flag.NArg() == 0 {
fmt.Printf("%s: <dir>\n", os.Args[0])
flag.Usage()
}
if *sourceloc == "" {
log.Fatal("Need a source location")
}
images, err := ioutil.ReadDir(flag.Arg(0))
if err != nil {
panic(err)
}
for _, image := range images {
if strings.HasSuffix(image.Name(), ".json") {
log.Printf("Skipped %s...", image)
continue
}
fout, err := os.Create(image.Name() + ".json")
var i UploadImage
i.Image.SourceURL = *sourceloc
i.Image.ImageURL = *serverloc + filepath.Base(image.Name())
i.Image.Tags = "explicit"
if *set != "" {
i.Image.Tags = i.Image.Tags + ", comic:" + *set
}
outdata, err := json.MarshalIndent(&i, "", "\t")
if err != nil {
panic(err)
}
fout.Write(outdata)
fout.Close()
}
}

View File

@ -1,11 +0,0 @@
#!/bin/sh
cat << EOF
{
"image": {
"source_url": "$1",
"tag_list": "$2",
"image_url": "$3"
}
}
EOF

View File

@ -1,116 +0,0 @@
package main
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"strings"
"time"
)
var (
apiKeyLocation = flag.String("apikeyloc", "/home/xena/.local/share/within/db.key", "Derpibooru API key location")
cookieLocation = flag.String("cookieloc", "/home/xena/.db.cookie", "Location for magic cookie")
)
func main() {
flag.Parse()
if flag.NArg() == 0 {
fmt.Printf("%s: <image to upload>\n", os.Args[0])
fmt.Printf("All files must have a manifest json file.\n")
flag.Usage()
}
dbkey, err := ioutil.ReadFile(*apiKeyLocation)
if err != nil {
panic(err)
}
mydbkey := strings.Split(string(dbkey), "\n")[0]
cookie, err := ioutil.ReadFile(*cookieLocation)
if err != nil {
panic(err)
}
image := flag.Arg(0)
if strings.HasSuffix(image, ".json") {
log.Printf("Skipped %s...", image)
return
}
metafin, err := os.Open(image + ".json")
if err != nil {
log.Fatal("image " + image + " MUST have description manifest for derpibooru")
}
defer metafin.Close()
metabytes, err := ioutil.ReadAll(metafin)
if err != nil {
log.Fatal(err)
}
var meta UploadImage
err = json.Unmarshal(metabytes, &meta)
if err != nil {
log.Fatal(err)
}
imfin, err := os.Open(image)
if err != nil {
log.Fatal("cannot open " + image)
}
defer imfin.Close()
if meta.Image.ImageURL == "" {
panic("need file uploaded somewhere?")
}
outmetabytes, err := json.Marshal(&meta)
req, err := http.NewRequest("POST", "https://derpibooru.org/images.json?key="+mydbkey, bytes.NewBuffer(outmetabytes))
if err != nil {
panic(err)
}
c := &http.Client{}
req.Header = http.Header{
"User-Agent": {"Xena's crappy upload tool"},
"Cookie": {string(cookie)},
"Content-Type": {"application/json"},
}
resp, err := c.Do(req)
if err != nil {
log.Printf("%#v", err)
fmt.Printf("Request ID: %s\n", resp.Header.Get("X-Request-Id"))
return
}
if resp.StatusCode != 201 {
io.Copy(os.Stdout, resp.Body)
return
}
respbytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println(err)
return
}
var i Image
json.Unmarshal(respbytes, &i)
fmt.Printf("Uploaded as https://derpibooru.org/%d\n", i.IDNumber)
time.Sleep(20 * time.Second)
}

View File

@ -1,94 +0,0 @@
package main
import (
"bytes"
"log"
"os/exec"
"strings"
"time"
"github.com/bwmarrin/discordgo"
"github.com/namsral/flag"
)
var (
cfg = flag.String("config", "/home/xena/.local/share/within/discordaway.cfg", "configuration file")
username = flag.String("username", "", "Discord username to use")
password = flag.String("password", "", "Discord password to use")
)
func main() {
flag.Parse()
dg, err := discordgo.New(*username, *password)
if err != nil {
log.Fatal(err)
}
dg.AddHandler(messageCreate)
err = dg.Open()
if err != nil {
log.Fatal(err)
}
log.Println("monitoring tmux status...")
t := time.NewTicker(300 * time.Second)
ok, err := isTmuxAttached()
log.Println(ok, err)
for {
select {
case <-t.C:
at, err := isTmuxAttached()
if err != nil {
log.Println(err)
return
}
if at {
log.Println("Cadey is away, marking as away on Discord")
dg.UpdateStatus(600, "around with reality for some reason")
} else {
log.Println("Cadey is back!!!")
dg.UpdateStatus(0, "")
}
}
}
}
func isTmuxAttached() (bool, error) {
cmd := exec.Command("/usr/bin/tmux", "ls", "-F", "#{?session_attached,attached,not attached}")
output, err := cmd.Output()
if err != nil {
return false, err
}
return bytes.HasPrefix(output, []byte("attached")), nil
}
func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
if m.Author.ID == "72838115944828928" {
content := m.ContentWithMentionsReplaced()
if strings.HasPrefix(content, "TODO: ") {
todoBody := strings.SplitN(content, "TODO: ", 2)[1]
log.Printf("todo added: %s", todoBody)
todoFields := strings.Fields(todoBody)
cmd := exec.Command("/home/xena/go/bin/todo", append([]string{"add"}, todoFields...)...)
err := cmd.Start()
if err != nil {
log.Println(err)
return
}
err = cmd.Wait()
if err != nil {
log.Println(err)
}
}
}
}

View File

@ -1 +0,0 @@
dokku

View File

@ -1,55 +0,0 @@
Dokku
=====
This is a simple command line tool to interface with Dokku servers. This is
a port of my shell extension
[`dokku.zsh`](https://github.com/Xe/dotfiles/blob/master/.zsh/dokku.zsh) to
a nice Go binary.
This takes a configuration file for defining multiple servers:
```ini
[server "default"]
user = dokku
host = panel.apps.xeserv.us
sshkey = /.ssh/id_rsa
```
By default it will imply that the SSH key is `~/.ssh/id_rsa` and that the
username is `dokku`. By default the server named `default` will be used for
command execution.
TODO
----
- [ ] Allow interactive commands
- [ ] Directly pipe stdin and stdout to the ssh connection
---
```
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
```

View File

@ -1,11 +0,0 @@
package main
type Config struct {
Server map[string]*Server
}
type Server struct {
SSHKey string // if blank default key will be used.
Host string // hostname of the dokku server
User string // if blank username will be dokku
}

View File

@ -1,2 +0,0 @@
[server "default"]
host = panel.apps.xeserv.us

View File

@ -1,61 +0,0 @@
package main // christine.website/go/tools/dokku
import (
"flag"
"fmt"
"log"
"os"
"strings"
"code.google.com/p/gcfg"
"github.com/hypersleep/easyssh"
)
var (
cfgPath = flag.String("cfg", "", "configuration path, default is ~/.dokku.cfg")
serverName = flag.String("server", "default", "server to use out of dokku config")
)
func main() {
flag.Parse()
if *cfgPath == "" {
*cfgPath = os.Getenv("HOME") + "/.dokku.cfg"
}
var cfg Config
err := gcfg.ReadFileInto(&cfg, *cfgPath)
if err != nil {
log.Fatal(err)
}
var server *Server
var ok bool
if server, ok = cfg.Server[*serverName]; !ok {
log.Fatalf("server %s not defined in configuration file %s", *serverName, *cfgPath)
}
if server.User == "" {
server.User = "dokku"
}
if server.SSHKey == "" {
server.SSHKey = "/.ssh/id_rsa"
}
ssh := &easyssh.MakeConfig{
User: server.User,
Server: server.Host,
Key: server.SSHKey,
}
command := strings.Join(flag.Args(), " ")
res, err := ssh.Run(command)
if err != nil {
log.Fatal(err)
}
fmt.Print(res)
}

View File

@ -1 +0,0 @@
ghstat

View File

@ -1,9 +0,0 @@
# ghstat
--
Command ghstat shows the status of GitHub via their status API.
Usage of ./ghstat:
-message=false: show last message?
This follows https://status.github.com/api for all but the list of all recent
status messages.

View File

@ -1,10 +0,0 @@
/*
Command ghstat shows the status of GitHub via their status API.
Usage of ./ghstat:
-message=false: show last message?
This follows https://status.github.com/api for all but the list of all
recent status messages.
*/
package main

View File

@ -1,54 +0,0 @@
package main
import (
"flag"
"fmt"
"log"
"os"
"time"
)
var (
messageFlag = flag.Bool("message", false, "show last message?")
// TODO: implement
//shellFlag = flag.Bool("s", false, "show as shell prompt artifact")
)
func main() {
flag.Parse()
if *messageFlag {
m, err := getMessage()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Last message:\n")
fmt.Printf("Status: %s\n", m.Status)
fmt.Printf("Message: %s\n", m.Body)
t, err := time.Parse(time.RFC3339, m.CreatedOn)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Time: %s\n", t.Format(time.ANSIC))
} else {
s, err := getStatus()
if err != nil {
log.Fatal(err)
}
t, err := time.Parse(time.RFC3339, s.LastUpdated)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Status: %s (%s)\n", s.Status, t.Format(time.ANSIC))
if s.Status != "good" {
os.Exit(1)
}
}
}

View File

@ -1,60 +0,0 @@
package main
import (
"encoding/json"
"io/ioutil"
"net/http"
)
type Status struct {
Status string `json:"status"`
LastUpdated string `json:"last_updated"`
}
type Message struct {
Status string `json:"status"`
Body string `json:"body"`
CreatedOn string `json:"created_on"`
}
func getMessage() (Message, error) {
m := Message{}
resp, err := http.Get("https://status.github.com/api/last-message.json")
if err != nil {
return Message{}, err
}
defer resp.Body.Close()
content, err := ioutil.ReadAll(resp.Body)
if err != nil {
return Message{}, err
}
err = json.Unmarshal(content, &m)
if err != nil {
return Message{}, err
}
return m, nil
}
func getStatus() (Status, error) {
s := Status{}
resp, err := http.Get("https://status.github.com/api/status.json")
if err != nil {
return Status{}, err
}
defer resp.Body.Close()
content, err := ioutil.ReadAll(resp.Body)
if err != nil {
return Status{}, err
}
err = json.Unmarshal(content, &s)
if err != nil {
return Status{}, err
}
return s, nil
}

View File

@ -1,661 +0,0 @@
## `json`
```lua
local json = require "json"
```
Json encoder/decoder
The following functions are exposed by the library:
decode(string): Decodes a JSON string. Returns nil and an error string if
the string could not be decoded.
encode(value): Encodes a value into a JSON string. Returns nil and an error
string if the value could not be encoded.
## `xmlpath`
```lua
local xmlpath = require "xmlpath"
```
XMLPath style iteration
xml ="<bookist><book>x1</book><book>x2</book><book>x3</book></booklist>"
local xmlpath = require("xmlpath")
node,err = xmlpath.loadxml(xml)
path,err = xmlpath.compile("//book")
it = path:iter(node)
for k,v in pairs(it) do
print(k,v:string())
end
## `http`
```lua
local http = require("http")
```
HTTP client library
### API
- [`http.delete(url [, options])`](#httpdeleteurl--options)
- [`http.get(url [, options])`](#httpgeturl--options)
- [`http.head(url [, options])`](#httpheadurl--options)
- [`http.patch(url [, options])`](#httppatchurl--options)
- [`http.post(url [, options])`](#httpposturl--options)
- [`http.put(url [, options])`](#httpputurl--options)
- [`http.request(method, url [, options])`](#httprequestmethod-url--options)
- [`http.request_batch(requests)`](#httprequest_batchrequests)
- [`http.response`](#httpresponse)
#### http.delete(url [, options])
**Attributes**
| Name | Type | Description |
| ------- | ------ | ----------- |
| url | String | URL of the resource to load |
| options | Table | Additional options |
**Options**
| Name | Type | Description |
| ------- | ------ | ----------- |
| query | String | URL encoded query params |
| cookies | Table | Additional cookies to send with the request |
| headers | Table | Additional headers to send with the request |
**Returns**
[http.response](#httpresponse) or (nil, error message)
#### http.get(url [, options])
**Attributes**
| Name | Type | Description |
| ------- | ------ | ----------- |
| url | String | URL of the resource to load |
| options | Table | Additional options |
**Options**
| Name | Type | Description |
| ------- | ------ | ----------- |
| query | String | URL encoded query params |
| cookies | Table | Additional cookies to send with the request |
| headers | Table | Additional headers to send with the request |
**Returns**
[http.response](#httpresponse) or (nil, error message)
#### http.head(url [, options])
**Attributes**
| Name | Type | Description |
| ------- | ------ | ----------- |
| url | String | URL of the resource to load |
| options | Table | Additional options |
**Options**
| Name | Type | Description |
| ------- | ------ | ----------- |
| query | String | URL encoded query params |
| cookies | Table | Additional cookies to send with the request |
| headers | Table | Additional headers to send with the request |
**Returns**
[http.response](#httpresponse) or (nil, error message)
#### http.patch(url [, options])
**Attributes**
| Name | Type | Description |
| ------- | ------ | ----------- |
| url | String | URL of the resource to load |
| options | Table | Additional options |
**Options**
| Name | Type | Description |
| ------- | ------ | ----------- |
| query | String | URL encoded query params |
| cookies | Table | Additional cookies to send with the request |
| body | String | Request body. |
| form | String | Deprecated. URL encoded request body. This will also set the `Content-Type` header to `application/x-www-form-urlencoded` |
| headers | Table | Additional headers to send with the request |
**Returns**
[http.response](#httpresponse) or (nil, error message)
#### http.post(url [, options])
**Attributes**
| Name | Type | Description |
| ------- | ------ | ----------- |
| url | String | URL of the resource to load |
| options | Table | Additional options |
**Options**
| Name | Type | Description |
| ------- | ------ | ----------- |
| query | String | URL encoded query params |
| cookies | Table | Additional cookies to send with the request |
| body | String | Request body. |
| form | String | Deprecated. URL encoded request body. This will also set the `Content-Type` header to `application/x-www-form-urlencoded` |
| headers | Table | Additional headers to send with the request |
**Returns**
[http.response](#httpresponse) or (nil, error message)
#### http.put(url [, options])
**Attributes**
| Name | Type | Description |
| ------- | ------ | ----------- |
| url | String | URL of the resource to load |
| options | Table | Additional options |
**Options**
| Name | Type | Description |
| ------- | ------ | ----------- |
| query | String | URL encoded query params |
| cookies | Table | Additional cookies to send with the request |
| body | String | Request body. |
| form | String | Deprecated. URL encoded request body. This will also set the `Content-Type` header to `application/x-www-form-urlencoded` |
| headers | Table | Additional headers to send with the request |
**Returns**
[http.response](#httpresponse) or (nil, error message)
#### http.request(method, url [, options])
**Attributes**
| Name | Type | Description |
| ------- | ------ | ----------- |
| method | String | The HTTP request method |
| url | String | URL of the resource to load |
| options | Table | Additional options |
**Options**
| Name | Type | Description |
| ------- | ------ | ----------- |
| query | String | URL encoded query params |
| cookies | Table | Additional cookies to send with the request |
| body | String | Request body. |
| form | String | Deprecated. URL encoded request body. This will also set the `Content-Type` header to `application/x-www-form-urlencoded` |
| headers | Table | Additional headers to send with the request |
**Returns**
[http.response](#httpresponse) or (nil, error message)
#### http.request_batch(requests)
**Attributes**
| Name | Type | Description |
| -------- | ----- | ----------- |
| requests | Table | A table of requests to send. Each request item is by itself a table containing [http.request](#httprequestmethod-url--options) parameters for the request |
**Returns**
[[http.response](#httpresponse)] or ([[http.response](#httpresponse)], [error message])
#### http.response
The `http.response` table contains information about a completed HTTP request.
**Attributes**
| Name | Type | Description |
| ----------- | ------ | ----------- |
| body | String | The HTTP response body |
| body_size | Number | The size of the HTTP reponse body in bytes |
| headers | Table | The HTTP response headers |
| cookies | Table | The cookies sent by the server in the HTTP response |
| status_code | Number | The HTTP response status code |
| url | String | The final URL the request ended pointing to after redirects |
## `url`
```lua
local url = require "url"
```
URL parsing library
### API
- [`url.parse(url)`](#urlparseurl)
- [`url.build(options)`](#urlbuildoptions)
- [`url.build_query_string(query_params)`](#urlbuild_query_stringquery_params)
- [`url.resolve(from, to)`](#urlresolvefrom-to)
#### url.parse(url)
Parse URL into a table of key/value components.
**Attributes**
| Name | Type | Description |
| ------- | ------ | ----------- |
| url | String | URL to parsed |
**Returns**
Table with parsed URL or (nil, error message)
| Name | Type | Description |
| -------- | ------ | ----------- |
| scheme | String | Scheme of the URL |
| username | String | Username |
| password | String | Password |
| host | String | Host and port of the URL |
| path | String | Path |
| query | String | Query string |
| fragment | String | Fragment |
#### url.build(options)
Assemble a URL string from a table of URL components.
**Attributes**
| Name | Type | Description |
| ------- | ----- | ----------- |
| options | Table | Table with URL components, see [`url.parse`](#urlparseurl) for list of valid components |
**Returns**
String
#### url.build_query_string(query_params)
Assemble table of query string parameters into a string.
**Attributes**
| Name | Type | Description |
| ------------ | ----- | ----------- |
| query_params | Table | Table with query parameters |
**Returns**
String
#### url.resolve(from, to)
Take a base URL, and a href URL, and resolve them as a browser would for an anchor tag.
| Name | Type | Description |
| ---- | ------ | ----------- |
| from | String | base URL |
| to | String | href URL |
**Returns**
String or (nil, error message)
## `env`
```lua
local env = require "env"
```
Environment manipulation
### API
#### `env.set(key, value)`
Same `os.setenv`
#### `env.get(key)`
Same `os.getenv`
#### `env.loadfile(file)`
Loads environment variables from a file. The file is as the following:
```
AAA=BBB
CCC=DDD
```
If this function fails, it returns `nil`, plus a string describing the error.
## `fs`
```lua
local fs = require "fs"
```
Filesystem manipulation
### API
#### `fs.exists(file)`
Returns true if the file exists.
#### `fs.read(file)`
Reads file content and return it. If this function fails, it returns `nil`, plus a string describing the error.
#### `fs.write(file, content, [mode])`
Writes content to the file. If this function fails, it returns `nil`, plus a string describing the error.
#### `fs.mkdir(path, [mode, recursive])`
Create directory. If this function fails, it returns `nil`, plus a string describing the error.
#### `fs.remove(path, [recursive])`
Remove path. If this function fails, it returns `nil`, plus a string describing the error.
#### `fs.symlink(target, link)`
Create symbolic link. If this function fails, it returns `nil`, plus a string describing the error.
#### `fs.dirname(path)`
Returns all but the last element of path.
#### `fs.basename(path)`
Returns the last element of path.
#### `fs.realpath(path)`
Returns the real path of a given path in the os. If this function fails, it returns `nil`, plus a string describing the error.
#### `fs.getcwd()`
Returns the current working directory. If this function fails, it returns `nil`, plus a string describing the error.
#### `fs.chdir(path)`
Changes the current working directory. If this function fails, it returns `nil`, plus a string describing the error.
#### `fs.file()`
Returns the script file path. If this function fails, it returns `nil`, plus a string describing the error.
#### `fs.dir()`
Returns the directory path that is parent of the script file. If this function fails, it returns `nil`, plus a string describing the error.
#### `fs.glob(pattern, function)`
Run the callback function with the files matching pattern. See below example:
```lua
local fs = require("fs")
local ret, err = fs.glob("/tmp/*", function(file)
print(file.path)
print(file.realpath)
end)
```
## `markdown`
```lua
local markdown = require "markdown"
```
Markdown -> HTML for string and file
### API
#### `markdown.dostring(text)`
Returns HTML string generated from the markdown text.
#### `markdown.dofile(file)`
Returns HTML string generated from the markdown text file. If this function fails, it returns `nil`, plus a string describing the error.
## `question`
```lua
local question = require "question"
```
Prompt library
### API
* `question.ask(text)`
* `question.secret(text)`
## `ssh`
```lua
local ssh = require "ssh"
```
SSH client library
https://github.com/kohkimakimoto/gluassh/blob/master/gluassh_test.go
## `template`
```lua
local template = require "template"
```
Go text templates
### API
#### `template.dostring(text, table)`
Returns string generated by text template with the table values. If this function fails, it returns `nil`, plus a string describing the error.
#### `template.dofile(file, table)`
Returns string generated by file template with the table values. If this function fails, it returns `nil`, plus a string describing the error.
## `yaml`
```lua
local yaml = require "yaml"
```
Yaml -> table parser
### API
#### `yaml.parse(string)`
Parses yaml formatted string and returns a table. If this function fails, it returns `nil`, plus a string describing the error.
## `flag`
```lua
local flag = require "flag"
```
Command line flag parsing.
See the tests here: https://github.com/otm/gluaflag
```lua
local flag = require "flag"
fs = flag.new()
fs:string("name", "foo", "String help string")
fs:intArg("title", 1, "Title")
fs:numberArg("title", 1, "Title")
flags = fs:parse(arg) -- arg is the remaining command line arguments
assert(flags.title == 2, "expected title to be 2")
assert(flags.title == 2.32, "expected title to be 2.32")
```
## `sh`
```lua
local sh = require "sh"
```
gluash is a interface to call any program as it were a function. Programs are executed asynchronously to enable streaming of data in pipes.
In all discussions bellow the imported module will be referred to as `sh`.
Commands are called just like functions, executed on the sh module.
```lua
sh.ls("/")
```
For commands that have exotic names, names that are reserved words, or to execute absolute or relative paths call the sh module directly.
```lua
sh("/bin/ls", "/")
```
#### Multiple Arguments
Commands with multiple arguments have to be invoked with a separate string for each argument.
```lua
-- this works
sh.ls("-la", "/")
-- this does not work
sh.ls("-la /")
```
#### Piping
Piping in sh is done almost like piping in the shell. Just call next command as a method on the previous command.
```lua
sh.du("-sb"):sort("-rn"):print()
```
If the command has a exotic name, or a reserved word, call the command through `cmd(path, ...args)`. The first argument in `cmd` is the path.
```lua
sh.du("-sb"):cmd("sort", "-rn"):print()
```
### Waiting for Processes
All commands are executed by default in the background, so one have to explicitly wait for a process to finish. There are several ways to wait for the command to finish.
* `print()` - write stdout and stderr to stdout.
* `ok()` - aborts execution if the command's exit code is not zero
* `success()` - returns true of the commands exit code is zero
* `exitcode()` - returns the exit code of the command
### Abort by Default
It is possible to set the module to abort on errors without checking. It can be practical in some occasions, however performance will be degraded. When global exit code checks are done the commands are run in series, even in pipes, and output is saved in memory buffers.
To enable global exit code settings call the sh module with an table with the key `abort` set to true.
```lua
sh{abort=true}
```
To read current settings in the module call the module with an empty table.
```lua
configuration = sh{}
print("abort:", configuration.abort)
```
### Analyzing Output
There are several options to analyze the output of a command.
#### lines()
An iterator is accessible by calling the method `lines()` on the command.
```lua
for line in sh.cat("/etc/hosts"):lines() do
print(line)
end
```
#### stdout([filename]), stderr([filename]), combinedOutput([filename])
`stdout()`, `stderr()`, and `combinedOutput()` all returns the output of the command as a string. An optional `filename` can be given to the method, in that case the output is also written to the file. The file will be truncated.
```lua
-- print output of command
output = sh.echo("hello world"):combinedOutput("/tmp/output")
print(output)
```
In the example above will print `hello world` and it will write it to `/tmp/output`
### Glob Expansion
There is no glob expansion done on arguments, however there is a glob functionality in sh.
```lua
sh.ls(sh.glob("*.go"))
```
## `re`
```lua
local re = require "re"
```
Regular Expressions
### API
re.find , re.gsub, re.match, re.gmatch are available. These functions have the same API as Lua pattern match.
gluare uses the Go regexp package, so you can use regular expressions that are supported in the Go regexp package.
In addition, the following functions are defined:
```
gluare.quote(s string) -> string
Arguments:
s string: a string value to escape meta characters
Returns:
string: escaped string
gluare.quote returns a string that quotes all regular expression metacharacters inside the given text.
```
## `simplebox`
```lua
local simplebox = require "simplebox"
```
Simple encryption
### API
#### Create a new instance of simplebox with a newly generated key
```lua
local simplebox = require "simplebox"
local key = simplebox.genkey()
print("key is: " .. key)
local sb = simplebox.new()
```

View File

@ -1,4 +0,0 @@
FROM busybox
ADD glue /glue
CMD /glue

View File

@ -1,18 +0,0 @@
glue
====
Basically gopher-lua's cmd/glua with the following modules imported:
- https://godoc.org/layeh.com/gopher-json
- https://github.com/ailncode/gluaxmlpath
- https://github.com/cjoudrey/gluahttp
- https://github.com/cjoudrey/gluaurl
- https://github.com/kohkimakimoto/gluaenv
- https://github.com/kohkimakimoto/gluafs
- https://github.com/kohkimakimoto/gluamarkdown
- https://github.com/kohkimakimoto/gluaquestion
- https://github.com/kohkimakimoto/gluassh
- https://github.com/kohkimakimoto/gluatemplate
- https://github.com/kohkimakimoto/gluayaml
- https://github.com/otm/gluaflag
- https://github.com/otm/gluash
- https://github.com/yuin/gluare

View File

@ -1,6 +0,0 @@
from "alpine:edge"
copy "glue", "/glue"
cmd "/glue"
flatten
tag "xena/glue"

View File

@ -1,20 +0,0 @@
-- expects glue, $ go get -u github.com/Xe/tools/glue
local sh = require "sh"
sh { abort = true }
if os.getenv("CGO_ENABLED") ~= "0" then
error("CGO_ENABLED must be set to 1")
end
print "building glue..."
sh.go("build"):print()
sh.upx("--ultra-brute", "glue"):print()
sh.box("box.rb"):print()
print "releasing to docker hub"
sh.docker("push", "xena/glue"):print()
print "moving glue binary to $GOPATH/bin"
sh.mv("glue", (os.getenv("GOPATH") .. "/bin/glue"))
print "build/release complete"

View File

@ -1,215 +0,0 @@
package main
import (
"bufio"
"flag"
"fmt"
"net/http"
"os"
"runtime/pprof"
"github.com/Xe/tools/glue/libs/gluaexpect"
"github.com/Xe/tools/glue/libs/gluasimplebox"
"github.com/ailncode/gluaxmlpath"
"github.com/cjoudrey/gluahttp"
"github.com/cjoudrey/gluaurl"
"github.com/kohkimakimoto/gluaenv"
"github.com/kohkimakimoto/gluafs"
"github.com/kohkimakimoto/gluamarkdown"
"github.com/kohkimakimoto/gluaquestion"
"github.com/kohkimakimoto/gluassh"
"github.com/kohkimakimoto/gluatemplate"
"github.com/kohkimakimoto/gluayaml"
"github.com/otm/gluaflag"
"github.com/otm/gluash"
"github.com/yuin/gluare"
"github.com/yuin/gopher-lua"
"github.com/yuin/gopher-lua/parse"
json "layeh.com/gopher-json"
)
func main() {
os.Exit(mainAux())
}
func mainAux() int {
var opt_e, opt_l, opt_p string
var opt_i, opt_v, opt_dt, opt_dc bool
var opt_m int
flag.StringVar(&opt_e, "e", "", "")
flag.StringVar(&opt_l, "l", "", "")
flag.StringVar(&opt_p, "p", "", "")
flag.IntVar(&opt_m, "mx", 0, "")
flag.BoolVar(&opt_i, "i", false, "")
flag.BoolVar(&opt_v, "v", false, "")
flag.BoolVar(&opt_dt, "dt", false, "")
flag.BoolVar(&opt_dc, "dc", false, "")
flag.Usage = func() {
fmt.Println(`Usage: glue [options] [script [args]].
Available options are:
-e stat execute string 'stat'
-l name require library 'name'
-mx MB memory limit(default: unlimited)
-dt dump AST trees
-dc dump VM codes
-i enter interactive mode after executing 'script'
-p file write cpu profiles to the file
-v show version information
`)
}
flag.Parse()
if len(opt_p) != 0 {
f, err := os.Create(opt_p)
if err != nil {
fmt.Println(err.Error())
os.Exit(1)
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}
if len(opt_e) == 0 && !opt_i && !opt_v && flag.NArg() == 0 {
opt_i = true
}
status := 0
L := lua.NewState()
defer L.Close()
if opt_m > 0 {
L.SetMx(opt_m)
}
preload(L)
if opt_v || opt_i {
fmt.Println(lua.PackageCopyRight)
}
if len(opt_l) > 0 {
if err := L.DoFile(opt_l); err != nil {
fmt.Println(err.Error())
}
}
if nargs := flag.NArg(); nargs > 0 {
script := flag.Arg(0)
argtb := L.NewTable()
for i := 1; i < nargs; i++ {
L.RawSet(argtb, lua.LNumber(i), lua.LString(flag.Arg(i)))
}
L.SetGlobal("arg", argtb)
if opt_dt || opt_dc {
file, err := os.Open(script)
if err != nil {
fmt.Println(err.Error())
return 1
}
chunk, err2 := parse.Parse(file, script)
if err2 != nil {
fmt.Println(err2.Error())
return 1
}
if opt_dt {
fmt.Println(parse.Dump(chunk))
}
if opt_dc {
proto, err3 := lua.Compile(chunk, script)
if err3 != nil {
fmt.Println(err3.Error())
return 1
}
fmt.Println(proto.String())
}
}
if err := L.DoFile(script); err != nil {
fmt.Println(err.Error())
status = 1
}
}
if len(opt_e) > 0 {
if err := L.DoString(opt_e); err != nil {
fmt.Println(err.Error())
status = 1
}
}
if opt_i {
doREPL(L)
}
return status
}
func preload(L *lua.LState) {
L.PreloadModule("re", gluare.Loader)
L.PreloadModule("sh", gluash.Loader)
L.PreloadModule("markdown", gluamarkdown.Loader)
L.PreloadModule("fs", gluafs.Loader)
L.PreloadModule("env", gluaenv.Loader)
L.PreloadModule("yaml", gluayaml.Loader)
L.PreloadModule("question", gluaquestion.Loader)
L.PreloadModule("ssh", gluassh.Loader)
L.PreloadModule("http", gluahttp.NewHttpModule(&http.Client{}).Loader)
L.PreloadModule("flag", gluaflag.Loader)
L.PreloadModule("template", gluatemplate.Loader)
L.PreloadModule("url", gluaurl.Loader)
gluaexpect.Preload(L)
gluasimplebox.Preload(L)
gluaxmlpath.Preload(L)
json.Preload(L)
}
// do read/eval/print/loop
func doREPL(L *lua.LState) {
reader := bufio.NewReader(os.Stdin)
for {
if str, err := loadline(reader, L); err == nil {
if err := L.DoString(str); err != nil {
fmt.Println(err)
}
} else { // error on loadline
fmt.Println(err)
return
}
}
}
func incomplete(err error) bool {
if lerr, ok := err.(*lua.ApiError); ok {
if perr, ok := lerr.Cause.(*parse.Error); ok {
return perr.Pos.Line == parse.EOF
}
}
return false
}
func loadline(reader *bufio.Reader, L *lua.LState) (string, error) {
fmt.Print("> ")
if line, err := reader.ReadString('\n'); err == nil {
if _, err := L.LoadString("return " + line); err == nil { // try add return <...> then compile
return line, nil
} else {
return multiline(line, reader, L)
}
} else {
return "", err
}
}
func multiline(ml string, reader *bufio.Reader, L *lua.LState) (string, error) {
for {
if _, err := L.LoadString(ml); err == nil { // try compile
return ml, nil
} else if !incomplete(err) { // syntax error , but not EOF
return ml, nil
} else {
fmt.Print(">> ")
if line, err := reader.ReadString('\n'); err == nil {
ml = ml + "\n" + line
} else {
return "", err
}
}
}
}

View File

@ -1,35 +0,0 @@
package gluaexpect
import (
"github.com/ThomasRooney/gexpect"
lua "github.com/yuin/gopher-lua"
luar "layeh.com/gopher-luar"
)
func Preload(L *lua.LState) {
L.PreloadModule("expect", Loader)
}
// Loader is the module loader function.
func Loader(L *lua.LState) int {
mod := L.SetFuncs(L.NewTable(), api)
L.Push(mod)
return 1
}
var api = map[string]lua.LGFunction{
"spawn": spawn,
}
func spawn(L *lua.LState) int {
cmd := L.CheckString(1)
child, err := gexpect.Spawn(cmd)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(luar.New(L, child))
return 1
}

View File

@ -1,100 +0,0 @@
package gluasimplebox
import (
"crypto/rand"
"encoding/base64"
"encoding/hex"
"errors"
"github.com/brandur/simplebox"
lua "github.com/yuin/gopher-lua"
luar "layeh.com/gopher-luar"
)
func Preload(L *lua.LState) {
L.PreloadModule("simplebox", Loader)
}
// Loader is the module loader function.
func Loader(L *lua.LState) int {
mod := L.SetFuncs(L.NewTable(), api)
L.Push(mod)
return 1
}
var api = map[string]lua.LGFunction{
"new": newSecretBox,
"genkey": genKey,
}
func newSecretBox(L *lua.LState) int {
key := L.CheckString(1)
k, err := parseKey(key)
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
sb := simplebox.NewFromSecretKey(k)
L.Push(luar.New(L, &box{sb: sb}))
return 1
}
func genKey(L *lua.LState) int {
key, err := generateKey()
if err != nil {
L.Push(lua.LNil)
L.Push(lua.LString(err.Error()))
return 2
}
L.Push(lua.LString(base64.URLEncoding.EncodeToString(key[:])))
return 1
}
func generateKey() (*[32]byte, error) {
var k [32]byte
_, err := rand.Read(k[:])
if err != nil {
return nil, err
}
return &k, nil
}
func parseKey(s string) (*[32]byte, error) {
k := &[32]byte{}
raw, err := base64.URLEncoding.DecodeString(s)
if err != nil {
return nil, err
}
if n := copy(k[:], raw); n < len(k) {
return nil, errors.New("not valid")
}
return k, nil
}
type box struct {
sb *simplebox.SimpleBox
}
func (b *box) Encrypt(data string) string {
result := b.sb.Encrypt([]byte(data))
return hex.EncodeToString(result)
}
func (b *box) Decrypt(data string) (string, error) {
d, err := hex.DecodeString(data)
if err != nil {
return "", err
}
plain, err := b.sb.Decrypt([]byte(d))
if err != nil {
return "", err
}
return string(plain), nil
}

View File

@ -1,2 +0,0 @@
imagesize
output

Some files were not shown because too many files have changed in this diff Show More