Move things around, set up a more structured app
This commit is contained in:
parent
bde3d7da90
commit
f7df55f044
|
@ -0,0 +1,10 @@
|
|||
route
|
||||
=====
|
||||
|
||||
A simple cluster-friendly load balancer for singleton microservices.
|
||||
|
||||
TODO
|
||||
----
|
||||
|
||||
- [ ] Store stuff into RethinkDB
|
||||
- [ ] Add Let's Encrypt support in addition to a free tor hidden service with every domain routed
|
|
@ -0,0 +1,80 @@
|
|||
package database
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
|
||||
"git.xeserv.us/xena/route/routerpc"
|
||||
r "github.com/GoRethink/gorethink"
|
||||
)
|
||||
|
||||
type DB struct {
|
||||
s *r.Session
|
||||
}
|
||||
|
||||
func New(host, database string) (*DB, error) {
|
||||
session, err := r.Connect(r.ConnectOpts{
|
||||
Address: host,
|
||||
Database: database,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
db := &DB{
|
||||
s: session,
|
||||
}
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
var tables = []string{
|
||||
"certs",
|
||||
"routes",
|
||||
}
|
||||
|
||||
type Route struct {
|
||||
ID string `gorethink:"id,omitempty"`
|
||||
Hostname string `gorethink:"hostname"`
|
||||
OnionHostname string `gorethink:"onionhostname"`
|
||||
Token string `gorethink:"token"`
|
||||
OnionKey []byte `gorethink:"onionKey"` // PEM-encoded
|
||||
}
|
||||
|
||||
func (db *DB) SaveRoute(resp *routerpc.AddHostResponse) error {
|
||||
pemblock := &pem.Block{
|
||||
Type: "RSA PRIVATE KEY",
|
||||
Bytes: x509.MarshalPKCS1PrivateKey(resp.PrivKey.(*rsa.PrivateKey)),
|
||||
}
|
||||
bytes := pem.EncodeToMemory(pemblock)
|
||||
|
||||
rt := &Route{
|
||||
Hostname: resp.Hostname,
|
||||
OnionHostname: resp.OnionHostname,
|
||||
Token: resp.Token,
|
||||
OnionKey: bytes,
|
||||
}
|
||||
|
||||
_, err := r.Table("routes").Insert(rt).RunWrite(db.s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *DB) GetAllRoutes() ([]Route, error) {
|
||||
rows, err := r.Table("routes").Run(db.s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var routes []Route
|
||||
err = rows.All(&routes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return routes, nil
|
||||
}
|
|
@ -0,0 +1,505 @@
|
|||
/*
|
||||
Package elfs is this project's heroku style name generator.
|
||||
*/
|
||||
package elfs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
// Names is the name of every Pokemon from Pokemon Vietnamese Crystal.
|
||||
var Names = []string{
|
||||
"SEED",
|
||||
"GRASS",
|
||||
"FLOWE",
|
||||
"SHAD",
|
||||
"CABR",
|
||||
"SNAKE",
|
||||
"GOLD",
|
||||
"COW",
|
||||
"GUIKI",
|
||||
"PEDAL",
|
||||
"DELAN",
|
||||
"B-FLY",
|
||||
"BIDE",
|
||||
"KEYU",
|
||||
"FORK",
|
||||
"LAP",
|
||||
"PIGE",
|
||||
"PIJIA",
|
||||
"CAML",
|
||||
"LAT",
|
||||
"BIRD",
|
||||
"BABOO",
|
||||
"VIV",
|
||||
"ABOKE",
|
||||
"PIKAQ",
|
||||
"RYE",
|
||||
"SAN",
|
||||
"BREAD",
|
||||
"LIDEL",
|
||||
"LIDE",
|
||||
"PIP",
|
||||
"PIKEX",
|
||||
"ROK",
|
||||
"JUGEN",
|
||||
"PUD",
|
||||
"BUDE",
|
||||
"ZHIB",
|
||||
"GELU",
|
||||
"GRAS",
|
||||
"FLOW",
|
||||
"LAFUL",
|
||||
"ATH",
|
||||
"BALA",
|
||||
"CORN",
|
||||
"MOLUF",
|
||||
"DESP",
|
||||
"DAKED",
|
||||
"MIMI",
|
||||
"BOLUX",
|
||||
"KODA",
|
||||
"GELUD",
|
||||
"MONK",
|
||||
"SUMOY",
|
||||
"GEDI",
|
||||
"WENDI",
|
||||
"NILEM",
|
||||
"NILE",
|
||||
"NILEC",
|
||||
"KEZI",
|
||||
"YONGL",
|
||||
"HUDE",
|
||||
"WANLI",
|
||||
"GELI",
|
||||
"GUAIL",
|
||||
"MADAQ",
|
||||
"WUCI",
|
||||
"WUCI",
|
||||
"MUJEF",
|
||||
"JELLY",
|
||||
"SICIB",
|
||||
"GELU",
|
||||
"NELUO",
|
||||
"BOLI",
|
||||
"JIALE",
|
||||
"YED",
|
||||
"YEDE",
|
||||
"CLO",
|
||||
"SCARE",
|
||||
"AOCO",
|
||||
"DEDE",
|
||||
"DEDEI",
|
||||
"BAWU",
|
||||
"JIUG",
|
||||
"BADEB",
|
||||
"BADEB",
|
||||
"HOLE",
|
||||
"BALUX",
|
||||
"GES",
|
||||
"FANT",
|
||||
"QUAR",
|
||||
"YIHE",
|
||||
"SWAB",
|
||||
"SLIPP",
|
||||
"CLU",
|
||||
"DEPOS",
|
||||
"BILIY",
|
||||
"YUANO",
|
||||
"SOME",
|
||||
"NO",
|
||||
"YELA",
|
||||
"EMPT",
|
||||
"ZECUN",
|
||||
"XIAHE",
|
||||
"BOLEL",
|
||||
"DEJI",
|
||||
"MACID",
|
||||
"XIHON",
|
||||
"XITO",
|
||||
"LUCK",
|
||||
"MENJI",
|
||||
"GELU",
|
||||
"DECI",
|
||||
"XIDE",
|
||||
"DASAJ",
|
||||
"DONGN",
|
||||
"RICUL",
|
||||
"MINXI",
|
||||
"BALIY",
|
||||
"ZENDA",
|
||||
"LUZEL",
|
||||
"HELE5",
|
||||
"0FENB",
|
||||
"KAIL",
|
||||
"JIAND",
|
||||
"CARP",
|
||||
"JINDE",
|
||||
"LAPU",
|
||||
"MUDE",
|
||||
"YIFU",
|
||||
"LINLI",
|
||||
"SANDI",
|
||||
"HUSI",
|
||||
"JINC",
|
||||
"OUMU",
|
||||
"OUMUX",
|
||||
"CAP",
|
||||
"KUIZA",
|
||||
"PUD",
|
||||
"TIAO",
|
||||
"FRMAN",
|
||||
"CLAU",
|
||||
"SPARK",
|
||||
"DRAGO",
|
||||
"BOLIU",
|
||||
"GUAIL",
|
||||
"MIYOU",
|
||||
"MIY",
|
||||
"QIAOK",
|
||||
"BEIL",
|
||||
"MUKEI",
|
||||
"RIDED",
|
||||
"MADAM",
|
||||
"BAGEP",
|
||||
"CROC",
|
||||
"ALIGE",
|
||||
"OUDAL",
|
||||
"OUD",
|
||||
"DADA",
|
||||
"HEHE",
|
||||
"YEDEA",
|
||||
"NUXI",
|
||||
"NUXIN",
|
||||
"ROUY",
|
||||
"ALIAD",
|
||||
"STICK",
|
||||
"QIANG",
|
||||
"LAAND",
|
||||
"PIQI",
|
||||
"PI",
|
||||
"PUPI",
|
||||
"DEKE",
|
||||
"DEKEJ",
|
||||
"NADI",
|
||||
"NADIO",
|
||||
"MALI",
|
||||
"PEA",
|
||||
"ELECT",
|
||||
"FLOWE",
|
||||
"MAL",
|
||||
"MALI",
|
||||
"HUSHU",
|
||||
"NILEE",
|
||||
"YUZI",
|
||||
"POPOZ",
|
||||
"DUZI",
|
||||
"HEBA",
|
||||
"XIAN",
|
||||
"SHAN",
|
||||
"YEYEA",
|
||||
"WUY",
|
||||
"LUO",
|
||||
"KEFE",
|
||||
"HULA",
|
||||
"CROW",
|
||||
"YADEH",
|
||||
"MOW",
|
||||
"ANNAN",
|
||||
"SUONI",
|
||||
"KYLI",
|
||||
"HULU",
|
||||
"HUDEL",
|
||||
"YEHE",
|
||||
"GULAE",
|
||||
"YEHE",
|
||||
"BLU",
|
||||
"GELAN",
|
||||
"BOAT",
|
||||
"NIP",
|
||||
"POIT",
|
||||
"HELAK",
|
||||
"XINL",
|
||||
"BEAR",
|
||||
"LINB",
|
||||
"MAGEH",
|
||||
"MAGEJ",
|
||||
"WULI",
|
||||
"YIDE",
|
||||
"RIVE",
|
||||
"FISH",
|
||||
"AOGU",
|
||||
"DELIE",
|
||||
"MANTE",
|
||||
"KONMU",
|
||||
"DELU",
|
||||
"HELU",
|
||||
"HUAN",
|
||||
"HUMA",
|
||||
"DONGF",
|
||||
"JINCA",
|
||||
"HEDE",
|
||||
"DEFU",
|
||||
"LIBY",
|
||||
"JIAPA",
|
||||
"MEJI",
|
||||
"HELE",
|
||||
"BUHU",
|
||||
"MILK",
|
||||
"HABI",
|
||||
"THUN",
|
||||
"GARD",
|
||||
"DON",
|
||||
"YANGQ",
|
||||
"SANAQ",
|
||||
"BANQ",
|
||||
"LUJ",
|
||||
"PHIX",
|
||||
"SIEI",
|
||||
"EGG",
|
||||
}
|
||||
|
||||
// Moves is every single move from Pokemon Vietnamese Crystal.
|
||||
var Moves = []string{
|
||||
"ABLE",
|
||||
"ABNORMA",
|
||||
"AGAIN",
|
||||
"AIREXPL",
|
||||
"ANG",
|
||||
"ANGER",
|
||||
"ASAIL",
|
||||
"ATTACK",
|
||||
"AURORA",
|
||||
"AWL",
|
||||
"BAN",
|
||||
"BAND",
|
||||
"BARE",
|
||||
"BEAT",
|
||||
"BEATED",
|
||||
"BELLY",
|
||||
"BIND",
|
||||
"BITE",
|
||||
"BLOC",
|
||||
"BLOOD",
|
||||
"BODY",
|
||||
"BOOK",
|
||||
"BREATH",
|
||||
"BUMP",
|
||||
"CAST",
|
||||
"CHAM",
|
||||
"CLAMP",
|
||||
"CLAP",
|
||||
"CLAW",
|
||||
"CLEAR",
|
||||
"CLI",
|
||||
"CLIP",
|
||||
"CLOUD",
|
||||
"CONTRO",
|
||||
"CONVY",
|
||||
"COOLHIT",
|
||||
"CRASH",
|
||||
"CRY",
|
||||
"CUT",
|
||||
"DESCRI",
|
||||
"D-FIGHT",
|
||||
"DIG",
|
||||
"DITCH",
|
||||
"DIV",
|
||||
"DOZ",
|
||||
"DRE",
|
||||
"DUL",
|
||||
"DU-PIN",
|
||||
"DYE",
|
||||
"EARTH",
|
||||
"EDU",
|
||||
"EG-BOMB",
|
||||
"EGG",
|
||||
"ELEGY",
|
||||
"ELE-HIT",
|
||||
"EMBODY",
|
||||
"EMPLI",
|
||||
"ENGL",
|
||||
"ERUPT",
|
||||
"EVENS",
|
||||
"EXPLOR",
|
||||
"EYES",
|
||||
"FALL",
|
||||
"FAST",
|
||||
"F-CAR",
|
||||
"F-DANCE",
|
||||
"FEARS",
|
||||
"F-FIGHT",
|
||||
"FIGHT",
|
||||
"FIR",
|
||||
"FIRE",
|
||||
"FIREHIT",
|
||||
"FLAME",
|
||||
"FLAP",
|
||||
"FLASH",
|
||||
"FLEW",
|
||||
"FORCE",
|
||||
"FRA",
|
||||
"FREEZE",
|
||||
"FROG",
|
||||
"G-BIRD",
|
||||
"GENKISS",
|
||||
"GIFT",
|
||||
"G-KISS",
|
||||
"G-MOUSE",
|
||||
"GRADE",
|
||||
"GROW",
|
||||
"HAMMER",
|
||||
"HARD",
|
||||
"HAT",
|
||||
"HATE",
|
||||
"H-BOMB",
|
||||
"HELL-R",
|
||||
"HEMP",
|
||||
"HINT",
|
||||
"HIT",
|
||||
"HU",
|
||||
"HUNT",
|
||||
"HYPNOSI",
|
||||
"INHA",
|
||||
"IRO",
|
||||
"IRONBAR",
|
||||
"IR-WING",
|
||||
"J-GUN",
|
||||
"KEE",
|
||||
"KICK",
|
||||
"KNIF",
|
||||
"KNIFE",
|
||||
"KNOCK",
|
||||
"LEVEL",
|
||||
"LIGH",
|
||||
"LIGHHIT",
|
||||
"LIGHT",
|
||||
"LIVE",
|
||||
"L-WALL",
|
||||
"MAD",
|
||||
"MAJUS",
|
||||
"MEL",
|
||||
"MELO",
|
||||
"MESS",
|
||||
"MILK",
|
||||
"MIMI",
|
||||
"MISS",
|
||||
"MIXING",
|
||||
"MOVE",
|
||||
"MUD",
|
||||
"NI-BED",
|
||||
"NOISY",
|
||||
"NOONLI",
|
||||
"NULL",
|
||||
"N-WAVE",
|
||||
"PAT",
|
||||
"PEACE",
|
||||
"PIN",
|
||||
"PLAN",
|
||||
"PLANE",
|
||||
"POIS",
|
||||
"POL",
|
||||
"POWDE",
|
||||
"POWE",
|
||||
"POWER",
|
||||
"PRIZE",
|
||||
"PROTECT",
|
||||
"PROUD",
|
||||
"RAGE",
|
||||
"RECOR",
|
||||
"REFLAC",
|
||||
"REFREC",
|
||||
"REGR",
|
||||
"RELIV",
|
||||
"RENEW",
|
||||
"R-FIGHT",
|
||||
"RING",
|
||||
"RKICK",
|
||||
"ROCK",
|
||||
"ROUND",
|
||||
"RUS",
|
||||
"RUSH",
|
||||
"SAND",
|
||||
"SAW",
|
||||
"SCISSOR",
|
||||
"SCRA",
|
||||
"SCRIPT",
|
||||
"SEEN",
|
||||
"SERVER",
|
||||
"SHADOW",
|
||||
"SHELL",
|
||||
"SHINE",
|
||||
"SHO",
|
||||
"SIGHT",
|
||||
"SIN",
|
||||
"SMALL",
|
||||
"SMELT",
|
||||
"SMOK",
|
||||
"SNAKE",
|
||||
"SNO",
|
||||
"SNOW",
|
||||
"SOU",
|
||||
"SO-WAVE",
|
||||
"SPAR",
|
||||
"SPEC",
|
||||
"SPID",
|
||||
"S-PIN",
|
||||
"SPRA",
|
||||
"STAM",
|
||||
"STARE",
|
||||
"STEA",
|
||||
"STONE",
|
||||
"STORM",
|
||||
"STRU",
|
||||
"STRUG",
|
||||
"STUDEN",
|
||||
"SUBS",
|
||||
"SUCID",
|
||||
"SUN-LIG",
|
||||
"SUNRIS",
|
||||
"SUPLY",
|
||||
"S-WAVE",
|
||||
"TAILS",
|
||||
"TANGL",
|
||||
"TASTE",
|
||||
"TELLI",
|
||||
"THANK",
|
||||
"TONKICK",
|
||||
"TOOTH",
|
||||
"TORL",
|
||||
"TRAIN",
|
||||
"TRIKICK",
|
||||
"TUNGE",
|
||||
"VOLT",
|
||||
"WA-GUN",
|
||||
"WATCH",
|
||||
"WAVE",
|
||||
"W-BOMB",
|
||||
"WFALL",
|
||||
"WFING",
|
||||
"WHIP",
|
||||
"WHIRL",
|
||||
"WIND",
|
||||
"WOLF",
|
||||
"WOOD",
|
||||
"WOR",
|
||||
"YUJA",
|
||||
}
|
||||
|
||||
func randomMove() string {
|
||||
return Moves[rand.Intn(len(Moves))]
|
||||
}
|
||||
|
||||
func randomName() string {
|
||||
return Names[rand.Intn(len(Names))]
|
||||
}
|
||||
|
||||
// MakeName generates a new domain name based on the moves and Pokemon names
|
||||
// from Pokemon Vietnamese Crystal.
|
||||
func MakeName() string {
|
||||
move1 := randomMove()
|
||||
move2 := randomMove()
|
||||
poke := randomName()
|
||||
return fmt.Sprintf("%s-%s-%s", move1, move2, poke)
|
||||
}
|
|
@ -0,0 +1,225 @@
|
|||
{
|
||||
"ABLE",
|
||||
"ABNORMA",
|
||||
"AGAIN",
|
||||
"AIREXPL",
|
||||
"ANG",
|
||||
"ANGER",
|
||||
"ASAIL",
|
||||
"ATTACK",
|
||||
"AURORA",
|
||||
"AWL",
|
||||
"BAN",
|
||||
"BAND",
|
||||
"BARE",
|
||||
"BEAT",
|
||||
"BEATED",
|
||||
"BELLY",
|
||||
"BIND",
|
||||
"BITE",
|
||||
"BLOC",
|
||||
"BLOOD",
|
||||
"BODY",
|
||||
"BOOK",
|
||||
"BREATH",
|
||||
"BUMP",
|
||||
"CAST",
|
||||
"CHAM",
|
||||
"CLAMP",
|
||||
"CLAP",
|
||||
"CLAW",
|
||||
"CLEAR",
|
||||
"CLI",
|
||||
"CLIP",
|
||||
"CLOUD",
|
||||
"CONTRO",
|
||||
"CONVY",
|
||||
"COOLHIT",
|
||||
"CRASH",
|
||||
"CRY",
|
||||
"CUT",
|
||||
"DESCRI",
|
||||
"D-FIGHT",
|
||||
"DIG",
|
||||
"DITCH",
|
||||
"DIV",
|
||||
"DOZ",
|
||||
"DRE",
|
||||
"DUL",
|
||||
"DU-PIN",
|
||||
"DYE",
|
||||
"EARTH",
|
||||
"EDU",
|
||||
"EG-BOMB",
|
||||
"EGG",
|
||||
"ELEGY",
|
||||
"ELE-HIT",
|
||||
"EMBODY",
|
||||
"EMPLI",
|
||||
"ENGL",
|
||||
"ERUPT",
|
||||
"EVENS",
|
||||
"EXPLOR",
|
||||
"EYES",
|
||||
"FALL",
|
||||
"FAST",
|
||||
"F-CAR",
|
||||
"F-DANCE",
|
||||
"FEARS",
|
||||
"F-FIGHT",
|
||||
"FIGHT",
|
||||
"FIR",
|
||||
"FIRE",
|
||||
"FIREHIT",
|
||||
"FLAME",
|
||||
"FLAP",
|
||||
"FLASH",
|
||||
"FLEW",
|
||||
"FORCE",
|
||||
"FRA",
|
||||
"FREEZE",
|
||||
"FROG",
|
||||
"G-BIRD",
|
||||
"GENKISS",
|
||||
"GIFT",
|
||||
"G-KISS",
|
||||
"G-MOUSE",
|
||||
"GRADE",
|
||||
"GROW",
|
||||
"HAMMER",
|
||||
"HARD",
|
||||
"HAT",
|
||||
"HATE",
|
||||
"H-BOMB",
|
||||
"HELL-R",
|
||||
"HEMP",
|
||||
"HINT",
|
||||
"HIT",
|
||||
"HU",
|
||||
"HUNT",
|
||||
"HYPNOSI",
|
||||
"INHA",
|
||||
"IRO",
|
||||
"IRONBAR",
|
||||
"IR-WING",
|
||||
"J-GUN",
|
||||
"KEE",
|
||||
"KICK",
|
||||
"KNIF",
|
||||
"KNIFE",
|
||||
"KNOCK",
|
||||
"LEVEL",
|
||||
"LIGH",
|
||||
"LIGHHIT",
|
||||
"LIGHT",
|
||||
"LIVE",
|
||||
"L-WALL",
|
||||
"MAD",
|
||||
"MAJUS",
|
||||
"MEL",
|
||||
"MELO",
|
||||
"MESS",
|
||||
"MILK",
|
||||
"MIMI",
|
||||
"MISS",
|
||||
"MIXING",
|
||||
"MOVE",
|
||||
"MUD",
|
||||
"NI-BED",
|
||||
"NOISY",
|
||||
"NOONLI",
|
||||
"NULL",
|
||||
"N-WAVE",
|
||||
"PAT",
|
||||
"PEACE",
|
||||
"PIN",
|
||||
"PLAN",
|
||||
"PLANE",
|
||||
"POIS",
|
||||
"POL",
|
||||
"POWDE",
|
||||
"POWE",
|
||||
"POWER",
|
||||
"PRIZE",
|
||||
"PROTECT",
|
||||
"PROUD",
|
||||
"RAGE",
|
||||
"RECOR",
|
||||
"REFLAC",
|
||||
"REFREC",
|
||||
"REGR",
|
||||
"RELIV",
|
||||
"RENEW",
|
||||
"R-FIGHT",
|
||||
"RING",
|
||||
"RKICK",
|
||||
"ROCK",
|
||||
"ROUND",
|
||||
"RUS",
|
||||
"RUSH",
|
||||
"SAND",
|
||||
"SAW",
|
||||
"SCISSOR",
|
||||
"SCRA",
|
||||
"SCRIPT",
|
||||
"SEEN",
|
||||
"SERVER",
|
||||
"SHADOW",
|
||||
"SHELL",
|
||||
"SHINE",
|
||||
"SHO",
|
||||
"SIGHT",
|
||||
"SIN",
|
||||
"SMALL",
|
||||
"SMELT",
|
||||
"SMOK",
|
||||
"SNAKE",
|
||||
"SNO",
|
||||
"SNOW",
|
||||
"SOU",
|
||||
"SO-WAVE",
|
||||
"SPAR",
|
||||
"SPEC",
|
||||
"SPID",
|
||||
"S-PIN",
|
||||
"SPRA",
|
||||
"STAM",
|
||||
"STARE",
|
||||
"STEA",
|
||||
"STONE",
|
||||
"STORM",
|
||||
"STRU",
|
||||
"STRUG",
|
||||
"STUDEN",
|
||||
"SUBS",
|
||||
"SUCID",
|
||||
"SUN-LIG",
|
||||
"SUNRIS",
|
||||
"SUPLY",
|
||||
"S-WAVE",
|
||||
"TAILS",
|
||||
"TANGL",
|
||||
"TASTE",
|
||||
"TELLI",
|
||||
"THANK",
|
||||
"TONKICK",
|
||||
"TOOTH",
|
||||
"TORL",
|
||||
"TRAIN",
|
||||
"TRIKICK",
|
||||
"TUNGE",
|
||||
"VOLT",
|
||||
"WA-GUN",
|
||||
"WATCH",
|
||||
"WAVE",
|
||||
"W-BOMB",
|
||||
"WFALL",
|
||||
"WFING",
|
||||
"WHIP",
|
||||
"WHIRL",
|
||||
"WIND",
|
||||
"WOLF",
|
||||
"WOOD",
|
||||
"WOR",
|
||||
"YUJA",
|
||||
}
|
|
@ -0,0 +1,250 @@
|
|||
{
|
||||
"SEED",
|
||||
"GRASS",
|
||||
"FLOWE",
|
||||
"SHAD",
|
||||
"CABR",
|
||||
"SNAKE",
|
||||
"GOLD",
|
||||
"COW",
|
||||
"GUIKI",
|
||||
"PEDAL",
|
||||
"DELAN",
|
||||
"B-FLY",
|
||||
"BIDE",
|
||||
"KEYU",
|
||||
"FORK",
|
||||
"LAP",
|
||||
"PIGE",
|
||||
"PIJIA",
|
||||
"CAML",
|
||||
"LAT",
|
||||
"BIRD",
|
||||
"BABOO",
|
||||
"VIV",
|
||||
"ABOKE",
|
||||
"PIKAQ",
|
||||
"RYE",
|
||||
"SAN",
|
||||
"BREAD",
|
||||
"LIDEL",
|
||||
"LIDE",
|
||||
"PIP",
|
||||
"PIKEX",
|
||||
"ROK",
|
||||
"JUGEN",
|
||||
"PUD",
|
||||
"BUDE",
|
||||
"ZHIB",
|
||||
"GELU",
|
||||
"GRAS",
|
||||
"FLOW",
|
||||
"LAFUL",
|
||||
"ATH",
|
||||
"BALA",
|
||||
"CORN",
|
||||
"MOLUF",
|
||||
"DESP",
|
||||
"DAKED",
|
||||
"MIMI",
|
||||
"BOLUX",
|
||||
"KODA",
|
||||
"GELUD",
|
||||
"MONK",
|
||||
"SUMOY",
|
||||
"GEDI",
|
||||
"WENDI",
|
||||
"NILEM",
|
||||
"NILE",
|
||||
"NILEC",
|
||||
"KEZI",
|
||||
"YONGL",
|
||||
"HUDE",
|
||||
"WANLI",
|
||||
"GELI",
|
||||
"GUAIL",
|
||||
"MADAQ",
|
||||
"WUCI",
|
||||
"WUCI",
|
||||
"MUJEF",
|
||||
"JELLY",
|
||||
"SICIB",
|
||||
"GELU",
|
||||
"NELUO",
|
||||
"BOLI",
|
||||
"JIALE",
|
||||
"YED",
|
||||
"YEDE",
|
||||
"CLO",
|
||||
"SCARE",
|
||||
"AOCO",
|
||||
"DEDE",
|
||||
"DEDEI",
|
||||
"BAWU",
|
||||
"JIUG",
|
||||
"BADEB",
|
||||
"BADEB",
|
||||
"HOLE",
|
||||
"BALUX",
|
||||
"GES",
|
||||
"FANT",
|
||||
"QUAR",
|
||||
"YIHE",
|
||||
"SWAB",
|
||||
"SLIPP",
|
||||
"CLU",
|
||||
"DEPOS",
|
||||
"BILIY",
|
||||
"YUANO",
|
||||
"SOME",
|
||||
"NO",
|
||||
"YELA",
|
||||
"EMPT",
|
||||
"ZECUN",
|
||||
"XIAHE",
|
||||
"BOLEL",
|
||||
"DEJI",
|
||||
"MACID",
|
||||
"XIHON",
|
||||
"XITO",
|
||||
"LUCK",
|
||||
"MENJI",
|
||||
"GELU",
|
||||
"DECI",
|
||||
"XIDE",
|
||||
"DASAJ",
|
||||
"DONGN",
|
||||
"RICUL",
|
||||
"MINXI",
|
||||
"BALIY",
|
||||
"ZENDA",
|
||||
"LUZEL",
|
||||
"HELE5",
|
||||
"0FENB",
|
||||
"KAIL",
|
||||
"JIAND",
|
||||
"CARP",
|
||||
"JINDE",
|
||||
"LAPU",
|
||||
"MUDE",
|
||||
"YIFU",
|
||||
"LINLI",
|
||||
"SANDI",
|
||||
"HUSI",
|
||||
"JINC",
|
||||
"OUMU",
|
||||
"OUMUX",
|
||||
"CAP",
|
||||
"KUIZA",
|
||||
"PUD",
|
||||
"TIAO",
|
||||
"FRMAN",
|
||||
"CLAU",
|
||||
"SPARK",
|
||||
"DRAGO",
|
||||
"BOLIU",
|
||||
"GUAIL",
|
||||
"MIYOU",
|
||||
"MIY",
|
||||
"QIAOK",
|
||||
"BEIL",
|
||||
"MUKEI",
|
||||
"RIDED",
|
||||
"MADAM",
|
||||
"BAGEP",
|
||||
"CROC",
|
||||
"ALIGE",
|
||||
"OUDAL",
|
||||
"OUD",
|
||||
"DADA",
|
||||
"HEHE",
|
||||
"YEDEA",
|
||||
"NUXI",
|
||||
"NUXIN",
|
||||
"ROUY",
|
||||
"ALIAD",
|
||||
"STICK",
|
||||
"QIANG",
|
||||
"LAAND",
|
||||
"PIQI",
|
||||
"PI",
|
||||
"PUPI",
|
||||
"DEKE",
|
||||
"DEKEJ",
|
||||
"NADI",
|
||||
"NADIO",
|
||||
"MALI",
|
||||
"PEA",
|
||||
"ELECT",
|
||||
"FLOWE",
|
||||
"MAL",
|
||||
"MALI",
|
||||
"HUSHU",
|
||||
"NILEE",
|
||||
"YUZI",
|
||||
"POPOZ",
|
||||
"DUZI",
|
||||
"HEBA",
|
||||
"XIAN",
|
||||
"SHAN",
|
||||
"YEYEA",
|
||||
"WUY",
|
||||
"LUO",
|
||||
"KEFE",
|
||||
"HULA",
|
||||
"CROW",
|
||||
"YADEH",
|
||||
"MOW",
|
||||
"ANNAN",
|
||||
"SUONI",
|
||||
"KYLI",
|
||||
"HULU",
|
||||
"HUDEL",
|
||||
"YEHE",
|
||||
"GULAE",
|
||||
"YEHE",
|
||||
"BLU",
|
||||
"GELAN",
|
||||
"BOAT",
|
||||
"NIP",
|
||||
"POIT",
|
||||
"HELAK",
|
||||
"XINL",
|
||||
"BEAR",
|
||||
"LINB",
|
||||
"MAGEH",
|
||||
"MAGEJ",
|
||||
"WULI",
|
||||
"YIDE",
|
||||
"RIVE",
|
||||
"FISH",
|
||||
"AOGU",
|
||||
"DELIE",
|
||||
"MANTE",
|
||||
"KONMU",
|
||||
"DELU",
|
||||
"HELU",
|
||||
"HUAN",
|
||||
"HUMA",
|
||||
"DONGF",
|
||||
"JINCA",
|
||||
"HEDE",
|
||||
"DEFU",
|
||||
"LIBY",
|
||||
"JIAPA",
|
||||
"MEJI",
|
||||
"HELE",
|
||||
"BUHU",
|
||||
"MILK",
|
||||
"HABI",
|
||||
"THUN",
|
||||
"GARD",
|
||||
"DON",
|
||||
"YANGQ",
|
||||
"SANAQ",
|
||||
"BANQ",
|
||||
"LUJ",
|
||||
"PHIX",
|
||||
"SIEI",
|
||||
"EGG",
|
||||
}
|
206
main.go
206
main.go
|
@ -1,30 +1,17 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/rpc"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"git.xeserv.us/xena/route/routerpc"
|
||||
r "github.com/GoRethink/gorethink"
|
||||
"github.com/Xe/uuid"
|
||||
"github.com/Yawning/bulb"
|
||||
"git.xeserv.us/xena/route/server"
|
||||
|
||||
"github.com/facebookgo/flagenv"
|
||||
_ "github.com/joho/godotenv/autoload"
|
||||
"github.com/koding/tunnel"
|
||||
"github.com/sycamoreone/orc/tor"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -36,11 +23,7 @@ var (
|
|||
torHashedPassword = flag.String("tor-hashed-password", "", "Tor hashed password")
|
||||
torPassword = flag.String("tor-password", "hunter2", "Tor clear password")
|
||||
webPort = flag.String("web-port", "9234", "HTTP ingress port for backends and users")
|
||||
)
|
||||
|
||||
// RPC constants
|
||||
const (
|
||||
RPCPort uint16 = 39453
|
||||
domainSuffix = flag.String("domain-suffix", ".apps.xeserv.us", "Domain name suffix associated with the load balancer")
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -48,7 +31,7 @@ func main() {
|
|||
flagenv.Parse()
|
||||
rand.Seed(time.Now().Unix())
|
||||
|
||||
s, err := create(&ServerConfig{
|
||||
s, err := server.New(&server.ServerConfig{
|
||||
ControlHost: *controlHost,
|
||||
ControlKeyFile: *controlKeyFile,
|
||||
RethinkDBHost: *rethinkDBHost,
|
||||
|
@ -56,6 +39,8 @@ func main() {
|
|||
TorDataDir: *torDataDir,
|
||||
TorHashedPassword: *torHashedPassword,
|
||||
TorPassword: *torPassword,
|
||||
WebPort: *webPort,
|
||||
DomainSuffix: *domainSuffix,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
@ -74,182 +59,3 @@ func main() {
|
|||
|
||||
hs.Serve(l)
|
||||
}
|
||||
|
||||
// Server is the main server type
|
||||
type Server struct {
|
||||
cfg *ServerConfig
|
||||
|
||||
sess *r.Session
|
||||
|
||||
torCon *bulb.Conn
|
||||
torCmd *tor.Cmd
|
||||
torControlPath string
|
||||
|
||||
rpcS *rpc.Server
|
||||
rpcAddr string
|
||||
|
||||
ts *tunnel.Server
|
||||
}
|
||||
|
||||
// ServerConfig configures Server
|
||||
type ServerConfig struct {
|
||||
ControlHost, ControlKeyFile string
|
||||
RethinkDBHost, RethinkDBDatabase string
|
||||
TorDataDir, TorHashedPassword, TorPassword string
|
||||
}
|
||||
|
||||
func create(cfg *ServerConfig) (*Server, error) {
|
||||
session, err := r.Connect(r.ConnectOpts{
|
||||
Address: cfg.RethinkDBHost,
|
||||
Database: cfg.RethinkDBDatabase,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
torControlPath := filepath.Join(cfg.TorDataDir, fmt.Sprintf("%d.sock", rand.Int63()))
|
||||
|
||||
tc := tor.NewConfig()
|
||||
tc.Set("DataDirectory", cfg.TorDataDir)
|
||||
tc.Set("HashedControlPassword", cfg.TorHashedPassword)
|
||||
tc.Set("SocksPort", "0")
|
||||
cp := rand.Intn(64512) // 64k - 1k
|
||||
tc.Set("ControlPort", cp)
|
||||
|
||||
tc.Timeout = 30 * time.Second
|
||||
log.Println(tc.ToCmdLineFormat())
|
||||
|
||||
tcmd, err := tor.NewCmd(tc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = tcmd.Start()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
bc, err := bulb.Dial("tcp", "127.0.0.1:"+strconv.Itoa(cp))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = bc.Authenticate(cfg.TorPassword)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fin, err := os.Open(cfg.ControlKeyFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer fin.Close()
|
||||
|
||||
data, err := ioutil.ReadAll(fin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var block *pem.Block
|
||||
|
||||
block, _ = pem.Decode([]byte(data))
|
||||
pKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = bc.AddOnion([]bulb.OnionPortSpec{
|
||||
bulb.OnionPortSpec{
|
||||
VirtPort: RPCPort,
|
||||
Target: l.Addr().String(),
|
||||
},
|
||||
}, pKey, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rpcs := rpc.NewServer()
|
||||
|
||||
ts, err := tunnel.NewServer(&tunnel.ServerConfig{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := &Server{
|
||||
cfg: cfg,
|
||||
|
||||
sess: session,
|
||||
|
||||
torCon: bc,
|
||||
torCmd: tcmd,
|
||||
torControlPath: torControlPath,
|
||||
|
||||
rpcS: rpcs,
|
||||
rpcAddr: l.Addr().String(),
|
||||
|
||||
ts: ts,
|
||||
}
|
||||
|
||||
rpcs.RegisterName("Urls", &RPCServer{Server: s})
|
||||
go rpcs.Accept(l)
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *Server) onionPath(name string) string {
|
||||
return filepath.Join(s.cfg.TorDataDir, name)
|
||||
}
|
||||
|
||||
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if r.RequestURI == rpc.DefaultRPCPath {
|
||||
s.rpcS.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
s.ts.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
type RPCServer struct {
|
||||
*Server
|
||||
}
|
||||
|
||||
func (rs *RPCServer) AddHost(req routerpc.AddHostRequest, resp *routerpc.AddHostResponse) error {
|
||||
if req.APIKey != "hunter2" {
|
||||
return errors.New("invalid api key")
|
||||
}
|
||||
|
||||
token := uuid.New()
|
||||
|
||||
oi, err := rs.torCon.AddOnion([]bulb.OnionPortSpec{
|
||||
bulb.OnionPortSpec{
|
||||
VirtPort: 80,
|
||||
Target: "127.0.0.1:" + *webPort,
|
||||
},
|
||||
}, req.PrivKey, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp.OnionHostname = oi.OnionID + ".onion"
|
||||
resp.Token = token
|
||||
|
||||
if req.Hostname != "" {
|
||||
rs.Server.ts.AddHost(req.Hostname, token)
|
||||
resp.Hostname = req.Hostname
|
||||
}
|
||||
rs.Server.ts.AddHost(resp.OnionHostname, token)
|
||||
|
||||
if oi.PrivateKey != nil {
|
||||
resp.PrivKey = oi.PrivateKey
|
||||
} else {
|
||||
resp.PrivKey = req.PrivKey
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,263 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/rpc"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"git.xeserv.us/xena/route/database"
|
||||
"git.xeserv.us/xena/route/lib/elfs"
|
||||
"git.xeserv.us/xena/route/routerpc"
|
||||
"github.com/Xe/uuid"
|
||||
"github.com/Yawning/bulb"
|
||||
"github.com/koding/tunnel"
|
||||
"github.com/sycamoreone/orc/tor"
|
||||
)
|
||||
|
||||
// RPC constants
|
||||
const (
|
||||
RPCPort uint16 = 39453
|
||||
)
|
||||
|
||||
// Server is the main server type
|
||||
type Server struct {
|
||||
cfg *ServerConfig
|
||||
|
||||
db *database.DB
|
||||
|
||||
torCon *bulb.Conn
|
||||
torCmd *tor.Cmd
|
||||
torControlPath string
|
||||
|
||||
rpcS *rpc.Server
|
||||
rpcAddr string
|
||||
|
||||
ts *tunnel.Server
|
||||
}
|
||||
|
||||
// ServerConfig configures Server
|
||||
type ServerConfig struct {
|
||||
ControlHost, ControlKeyFile string
|
||||
RethinkDBHost, RethinkDBDatabase string
|
||||
TorDataDir, TorHashedPassword, TorPassword string
|
||||
WebPort, DomainSuffix string
|
||||
}
|
||||
|
||||
// New creates a new Server
|
||||
func New(cfg *ServerConfig) (*Server, error) {
|
||||
db, err := database.New(cfg.RethinkDBHost, cfg.RethinkDBDatabase)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
l, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
torControlPath := filepath.Join(cfg.TorDataDir, fmt.Sprintf("%d.sock", rand.Int63()))
|
||||
|
||||
tc := tor.NewConfig()
|
||||
tc.Set("DataDirectory", cfg.TorDataDir)
|
||||
tc.Set("HashedControlPassword", cfg.TorHashedPassword)
|
||||
tc.Set("SocksPort", "0")
|
||||
cp := rand.Intn(64512) // 64k - 1k
|
||||
tc.Set("ControlPort", cp)
|
||||
|
||||
tc.Timeout = 30 * time.Second
|
||||
log.Println(tc.ToCmdLineFormat())
|
||||
|
||||
tcmd, err := tor.NewCmd(tc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = tcmd.Start()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
bc, err := bulb.Dial("tcp", "127.0.0.1:"+strconv.Itoa(cp))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = bc.Authenticate(cfg.TorPassword)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fin, err := os.Open(cfg.ControlKeyFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer fin.Close()
|
||||
|
||||
data, err := ioutil.ReadAll(fin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var block *pem.Block
|
||||
|
||||
block, _ = pem.Decode([]byte(data))
|
||||
pKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = bc.AddOnion([]bulb.OnionPortSpec{
|
||||
bulb.OnionPortSpec{
|
||||
VirtPort: RPCPort,
|
||||
Target: l.Addr().String(),
|
||||
},
|
||||
}, pKey, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rpcs := rpc.NewServer()
|
||||
|
||||
ts, err := tunnel.NewServer(&tunnel.ServerConfig{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s := &Server{
|
||||
cfg: cfg,
|
||||
|
||||
db: db,
|
||||
|
||||
torCon: bc,
|
||||
torCmd: tcmd,
|
||||
torControlPath: torControlPath,
|
||||
|
||||
rpcS: rpcs,
|
||||
rpcAddr: l.Addr().String(),
|
||||
|
||||
ts: ts,
|
||||
}
|
||||
|
||||
rpcs.RegisterName("Urls", &RPCServer{Server: s})
|
||||
go rpcs.Accept(l)
|
||||
|
||||
err = s.restore()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *Server) onionPath(name string) string {
|
||||
return filepath.Join(s.cfg.TorDataDir, name)
|
||||
}
|
||||
|
||||
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if r.RequestURI == rpc.DefaultRPCPath {
|
||||
s.rpcS.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
s.ts.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func (s *Server) restore() error {
|
||||
rts, err := s.db.GetAllRoutes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, rt := range rts {
|
||||
var block *pem.Block
|
||||
|
||||
block, _ = pem.Decode([]byte(rt.OnionKey))
|
||||
pKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ports := []bulb.OnionPortSpec{
|
||||
genPortSpec(80, "127.0.0.1:"+s.cfg.WebPort),
|
||||
}
|
||||
|
||||
_, err = s.torCon.AddOnion(ports, pKey, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.ts.AddHost(rt.Hostname, rt.Token)
|
||||
s.ts.AddHost(rt.OnionHostname, rt.Token)
|
||||
|
||||
log.Printf("added: %s (%s)", rt.Hostname, rt.OnionHostname)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func genPortSpec(incoming uint16, outgoing string) bulb.OnionPortSpec {
|
||||
return bulb.OnionPortSpec{
|
||||
VirtPort: incoming,
|
||||
Target: outgoing,
|
||||
}
|
||||
}
|
||||
|
||||
// RPCServer is a Server wrapped to work inside the context of net/rpc
|
||||
type RPCServer struct {
|
||||
*Server
|
||||
}
|
||||
|
||||
func (rs *RPCServer) AddHost(req routerpc.AddHostRequest, resp *routerpc.AddHostResponse) error {
|
||||
if req.APIKey != "hunter2" {
|
||||
return errors.New("invalid api key")
|
||||
}
|
||||
|
||||
token := uuid.New()
|
||||
|
||||
oi, err := rs.torCon.AddOnion([]bulb.OnionPortSpec{
|
||||
bulb.OnionPortSpec{
|
||||
VirtPort: 80,
|
||||
Target: "127.0.0.1:" + rs.cfg.WebPort,
|
||||
},
|
||||
}, req.PrivKey, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp.OnionHostname = oi.OnionID + ".onion"
|
||||
resp.Token = token
|
||||
|
||||
if req.Hostname != "" {
|
||||
rs.Server.ts.AddHost(req.Hostname, token)
|
||||
resp.Hostname = req.Hostname
|
||||
} else {
|
||||
resp.Hostname = elfs.MakeName() + rs.cfg.DomainSuffix
|
||||
rs.ts.AddHost(resp.Hostname, token)
|
||||
}
|
||||
rs.Server.ts.AddHost(resp.OnionHostname, token)
|
||||
|
||||
if oi.PrivateKey != nil {
|
||||
resp.PrivKey = oi.PrivateKey
|
||||
} else {
|
||||
resp.PrivKey = req.PrivKey
|
||||
}
|
||||
|
||||
err = rs.db.SaveRoute(resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue