Compare commits

...

30 Commits

Author SHA1 Message Date
AJ ONeal 38ae4a4a86 creating install-to directory 5 years ago
AJ ONeal 7cf8c529dd minor windows fixes 5 years ago
AJ ONeal f266559cff don't echo command 5 years ago
AJ ONeal a4b8a43b32 script to generate tab file 5 years ago
AJ ONeal 944731f443 installer updates for zip/windows 5 years ago
AJ ONeal b6d4230de4 add some TODOs and a missing newline 5 years ago
AJ ONeal d381c28a0c clearer error for unavailable version 5 years ago
AJ ONeal 11b5474d1e add option separator 5 years ago
AJ ONeal da440ce000 add some preinstall/postinstall scripts 5 years ago
AJ ONeal b4b4b68bac add some preinstall/postinstall scripts 5 years ago
AJ ONeal 33dd835092 update mac/linux installer (and package fix) 5 years ago
AJ ONeal dafc02201f treat windows less differently 5 years ago
AJ ONeal 1c38262641 bugfix pathman / serviceman links windows 5 years ago
AJ ONeal 1f736a71be add draft install.cmd 5 years ago
AJ ONeal 3ca47d18cd bugfix tar.gz packaging 5 years ago
AJ ONeal c927f0c6c6 wip: simplifying install script 5 years ago
AJ ONeal 8308fe7af8 remove old installer stuff 5 years ago
AJ ONeal 512e79bbe0 output .zip for windows 5 years ago
AJ ONeal b13624444b output .tar.gz for everything 5 years ago
AJ ONeal 74230d93e2 copy directory via tar 5 years ago
AJ ONeal c40340939a npm install deps 5 years ago
AJ ONeal 860f852df9 set exec bits 5 years ago
AJ ONeal b3ddca4ae2 download pathman and serviceman 5 years ago
AJ ONeal d16822b23c add CHANGELOG.md 5 years ago
AJ ONeal 7bb71f07ca handle symlinks 5 years ago
AJ ONeal 1e733b6d6d WIP slim down installer 5 years ago
AJ ONeal c183ebc0b6 WIP: pre-package telebit 5 years ago
AJ ONeal 308b69da57 friendlier logging 5 years ago
AJ ONeal 0ffa20d8e9 better logging 5 years ago
AJ ONeal 5090134d72 Detect OS, CPU, and Release channel 5 years ago
  1. 4
      .gitignore
  2. 4
      CHANGELOG.md
  3. 3
      bin-public/telebit
  4. 1
      bin-public/telebit.cmd
  5. 756
      build-all.go
  6. 799
      package-lock.json
  7. 6
      package.json
  8. 50
      scripts/postinstall.js
  9. 53
      scripts/preinstall.js
  10. 61
      usr/share/dist/Library/LaunchDaemons/cloud.telebit.remote.plist.tpl
  11. 2
      usr/share/dist/bin/telebit.tpl
  12. 2
      usr/share/dist/bin/telebitd.tpl
  13. 64
      usr/share/dist/etc/skel/.config/systemd/user/telebit.service.tpl
  14. 70
      usr/share/dist/etc/skel/Library/LaunchAgents/cloud.telebit.remote.plist.tpl
  15. 67
      usr/share/dist/etc/systemd/system/telebit.service.tpl
  16. 14
      usr/share/gen-tab.sh
  17. 448
      usr/share/install-launcher.js
  18. 14
      usr/share/install.cmd
  19. 260
      usr/share/install.sh
  20. 591
      usr/share/install_helper.sh
  21. 5
      usr/share/telebitd.tpl.yml
  22. 97
      usr/share/template-launcher.js

4
.gitignore

@ -1,3 +1,7 @@
*.tar.gz
*.zip
telebit-stable-*
node_modules.*
*.*.sw*
etc/acme/

4
CHANGELOG.md

@ -0,0 +1,4 @@
# v0.20.8
- Add CHANGELOG.md
- Switch to serviceman

3
bin-public/telebit

@ -0,0 +1,3 @@
#!/usr/bin/env bash
"$(dirname $(dirname $0))/bin/node" "$(dirname $(dirname $0))/bin/telebit.js" "$@"
exit $?

1
bin-public/telebit.cmd

@ -0,0 +1 @@
@"%~dp0\..\bin\node" "%~dp0\..\bin\telebit.js" %*

756
build-all.go

@ -0,0 +1,756 @@
package main
import (
"archive/tar"
"archive/zip"
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
"os/exec"
"path/filepath"
"strings"
)
type pkg struct {
os string
arch string
ext string
exe string
}
// ReaderAtCloser is just what it sounds
type ReaderAtCloser interface {
io.ReaderAt
io.Reader
io.Closer
}
func main() {
nodeArches := map[string]string{
"windows": "win",
"darwin": "darwin",
"linux": "linux",
"amd64": "x64",
"386": "x86",
"armv7": "armv7l",
"armv6": "armv6l",
"arm64": "arm64",
//"armv8": "arm64",
}
pkgs := []pkg{
pkg{os: "darwin", arch: "amd64", ext: "tar.gz"},
pkg{os: "windows", arch: "amd64", ext: "zip", exe: ".exe"},
pkg{os: "windows", arch: "386", ext: "zip", exe: ".exe"},
pkg{os: "linux", arch: "amd64", ext: "tar.gz"},
//pkg{os: "linux", arch: "armv8", ext: "tar.gz"},
pkg{os: "linux", arch: "arm64", ext: "tar.gz"},
pkg{os: "linux", arch: "armv7", ext: "tar.gz"},
pkg{os: "linux", arch: "armv6", ext: "tar.gz"},
}
nodev := "10.16.0"
release := "stable"
// temp file for the zip
// TODO use mktemp
f, err := os.OpenFile(fmt.Sprintf("telebit-%s.zip", release), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
if nil != err {
panic(err)
}
// get from trusted git source
turl := fmt.Sprintf("https://git.rootprojects.org/root/telebit.js/archive/%s.zip", release)
resp, err := http.Get(turl)
if nil != err {
panic(err)
}
defer resp.Body.Close()
if resp.StatusCode >= 300 || resp.StatusCode < 200 {
log.Fatal("Bad deal on telebit download:", resp.Status)
}
_, err = io.Copy(f, resp.Body)
if nil != err {
panic(err)
}
err = f.Sync()
if nil != err {
panic(err)
}
// Get a copy of all the node modules
npmdir := "tmp-package-modules"
// TODO save bits /*
err = os.RemoveAll(npmdir)
if nil != err {
panic(err)
}
err = os.MkdirAll(npmdir, 0755)
if nil != err {
panic(err)
}
b, err := ioutil.ReadFile("package.json")
if nil != err {
panic(err)
}
err = ioutil.WriteFile(filepath.Join(npmdir, "package.json"), b, 0644)
if nil != err {
panic(err)
}
nodeExec, err := exec.LookPath("node")
if nil != err {
panic(err)
}
npmExec, err := exec.LookPath("npm")
if nil != err {
panic(err)
}
cmd := exec.Command(nodeExec, npmExec, "install")
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Dir = npmdir
err = cmd.Run()
if nil != err {
panic(err)
}
//*/
for i := range pkgs {
pkg := pkgs[i]
arch := pkg.arch
if "arm64" == arch {
// TODO switch the pathman and serviceman URLs
arch = "armv8"
}
fmt.Printf("\nOS: %s\nArch: %s\n", pkg.os, arch)
// Create a fresh directory for this telebit release
outdir := fmt.Sprintf("telebit-%s-%s-%s", release, pkg.os, pkg.arch)
fmt.Printf("(clean) Release:%s\n", outdir)
err := os.RemoveAll(outdir)
if nil != err {
panic(err)
}
nos := nodeArches[pkg.os]
narch := nodeArches[pkg.arch]
// Grab the node files
npath := fmt.Sprintf("node-v%s-%s-%s", nodev, nos, narch)
nfile := fmt.Sprintf("%s.%s", npath, pkg.ext)
// TODO check remote filesize anyway as a quick sanity check
nurl := fmt.Sprintf("https://nodejs.org/download/release/v%s/%s", nodev, nfile)
err = download("node package", nurl, nfile, false)
if nil != err {
panic(err)
}
// lay down the node directory first
fmt.Printf("Unpacking %s %s\n", nfile, pkg.ext)
switch pkg.ext {
case "zip":
z, err := os.Open(nfile)
if nil != err {
panic(err)
}
s, err := z.Stat()
if nil != err {
panic(err)
}
strip := 1
if "windows" == pkg.os {
// re-nest into "bin" for consistency
err = unzip(z, s.Size(), filepath.Join(outdir, "bin"), strip)
// handle the special case of git bash
sh := strings.Join([]string{
`#!/usr/bin/env bash`,
`"$(dirname "$0")/node.exe" "$@"`,
`exit $?`,
}, "\n")
script := filepath.Join(outdir, "bin", "node")
if err := ioutil.WriteFile(script, []byte(sh), 0755); nil != err {
panic(err)
}
} else {
err = unzip(z, s.Size(), outdir, strip)
}
if nil != err {
panic(err)
}
case "tar.gz":
// SAVE ON BITS /*
tgz, err := os.Open(nfile)
if nil != err {
panic(err)
}
defer tgz.Close()
tarfile, err := gzip.NewReader(tgz)
if nil != err {
panic(err)
}
// TODOD XXX turn back on
strip := 1
err = untar(tarfile, outdir, strip)
if nil != err {
panic(err)
}
//*/
default:
panic(fmt.Errorf("%s", "Liar!!"))
}
// TODO how to handle node modules?
// overlay our stuff on top of the node release package
z, err := os.Open(fmt.Sprintf("telebit-%s.zip", release))
fmt.Printf("Overlaying %s\n", outdir)
if nil != err {
panic(err)
}
defer z.Close()
s, err := z.Stat()
if nil != err {
panic(err)
}
strip := 1
if err := unzip(z, s.Size(), outdir, strip); nil != err {
panic(err)
}
pr, pw := io.Pipe()
go func() {
tw := tar.NewWriter(pw)
defer tw.Close()
//fis, err := ioutil.ReadDir(npmdir)
fi, err := os.Stat(npmdir)
if nil != err {
panic("stat:" + err.Error())
}
//err = tarDir(tw, npmdir, fis, "")
err = tarEntry(tw, "", fi, "")
if nil != err {
panic("tarError:" + err.Error())
}
}()
err = untar(pr, outdir, 1)
if nil != err {
panic("untarError:" + err.Error())
}
// Get pathman for the platform
pathmanURL := fmt.Sprintf(
"https://rootprojects.org/pathman/dist/%s/%s/pathman"+pkg.exe,
pkg.os,
arch,
)
pathmanFile := filepath.Join(outdir, "node_modules/.bin", "pathman") + pkg.exe
err = download("pathman", pathmanURL, pathmanFile, true)
if nil != err {
panic(err)
}
if ".exe" == pkg.exe {
sh := strings.Join([]string{
`#!/usr/bin/env bash`,
`"$(dirname "$0")/pathman.exe" "$@"`,
`exit $?`,
}, "\n")
script := filepath.Join(outdir, "node_modules/.bin", "pathman")
if err := ioutil.WriteFile(script, []byte(sh), 0755); nil != err {
panic(err)
}
}
// Get serviceman for the platform
servicemanURL := fmt.Sprintf(
"https://rootprojects.org/serviceman/dist/%s/%s/serviceman"+pkg.exe,
pkg.os,
arch,
)
servicemanFile := filepath.Join(outdir, "node_modules/.bin", "serviceman") + pkg.exe
err = download("serviceman", servicemanURL, servicemanFile, true)
if nil != err {
panic(err)
}
if ".exe" == pkg.exe {
sh := strings.Join([]string{
`#!/usr/bin/env bash`,
`"$(dirname "$0")/serviceman.exe" "$@"`,
`exit $?`,
}, "\n")
script := filepath.Join(outdir, "node_modules/.bin", "serviceman")
if err := ioutil.WriteFile(script, []byte(sh), 0755); nil != err {
panic(err)
}
}
// Write out the packaged deliverable
f, err := os.OpenFile(outdir+"."+pkg.ext, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
defer f.Close()
if nil != err {
panic(err)
}
//fis, err := ioutil.ReadDir(npmdir)
fi, err := os.Stat(outdir)
if nil != err {
panic("stat:" + err.Error())
}
switch pkg.ext {
case "zip":
err = Zip(f, outdir, "")
if nil != err {
panic("zipError:" + err.Error())
}
case "tar.gz":
// Write out the tar
zw := gzip.NewWriter(f)
defer zw.Close()
tw := tar.NewWriter(zw)
defer tw.Close()
// TODO create Tar() in go-examples
//err = tarDir(tw, outdir, fis, "")
err = tarEntry(tw, "", fi, outdir)
if nil != err {
panic("tarError:" + err.Error())
}
// Explicitly close in the correct order
err = tw.Close()
if nil != err {
panic(err)
}
err = zw.Close()
if nil != err {
panic(err)
}
default:
panic(fmt.Errorf("%s", "Liar!!"))
}
err = f.Close()
if nil != err {
panic(err)
}
fmt.Println("wrote", outdir+"."+pkg.ext)
}
fmt.Printf("Done.\n")
}
func download(title string, nurl string, nfile string, exec bool) error {
if _, err := os.Stat(nfile); nil == err {
return nil
}
// doesn't exist, go grab it
fmt.Printf("Downloading %s to %s\n", nurl, nfile)
resp, err := http.Get(nurl)
if nil != err {
return err
}
if resp.StatusCode >= 300 || resp.StatusCode < 200 {
log.Fatal("Bad deal on download:", resp.Status)
}
defer resp.Body.Close()
// Stream it in locally
fmt.Printf("Streaming %s to %s\n", nurl, nfile)
fmode := os.FileMode(0644)
if exec {
fmode = os.FileMode(0755)
}
nf, err := os.OpenFile(nfile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, fmode)
_, err = io.Copy(nf, resp.Body)
if nil != err {
return err
}
return nf.Sync()
}
func untar(t io.Reader, outdir string, strip int) error {
tr := tar.NewReader(t)
for {
header, err := tr.Next()
if err == io.EOF {
break
}
if nil != err {
return err
}
fpath := stripPrefix(header.Name, strip)
fpath = filepath.Join(outdir, fpath)
switch header.Typeflag {
case tar.TypeLink:
// ignore hard links
case tar.TypeSymlink:
//fmt.Println("untarSym:", fpath)
// Note: the link itself is always a file, even when it represents a directory
lpath := filepath.Join(filepath.Dir(fpath), header.Linkname)
if !strings.HasPrefix(lpath+string(os.PathSeparator), outdir+string(os.PathSeparator)) {
return fmt.Errorf("Malicious link path: %s", header.Linkname)
}
if err := os.Symlink(header.Linkname, fpath); nil != err {
return err
}
case tar.TypeDir:
//fmt.Println("untarDir:", fpath)
/*
// TODO
if err := os.Lchown(dst); err != nil {
return err
}
*/
// gonna use the same perms as were set previously here
// should be fine (i.e. we want 755 for execs on *nix)
_, err := safeOpen(header.FileInfo(), os.FileMode(header.Mode), fpath, outdir)
if nil != err {
return err
}
case tar.TypeReg:
//fmt.Println("untarReg:", fpath)
/*
// TODO
if err := os.Lchown(dst); err != nil {
return err
}
*/
// gonna use the same perms as were set previously here
// should be fine (i.e. we want 755 for execs on *nix)
out, err := safeOpen(header.FileInfo(), os.FileMode(header.Mode), fpath, outdir)
if nil != err {
return err
}
defer out.Close()
_, err = io.Copy(out, tr)
if nil != err {
return err
}
err = out.Close()
if nil != err {
return err
}
default:
fmt.Printf("[debug] odd type %s (%c)", fpath, header.Typeflag)
}
}
return nil
}
func unzip(z io.ReaderAt, size int64, outdir string, strip int) error {
zr, err := zip.NewReader(z, size)
if nil != err {
return err
}
for i := range zr.File {
f := zr.File[i]
fpath := stripPrefix(f.Name, strip)
fpath = filepath.Join(outdir, fpath)
out, err := safeOpen(f.FileInfo(), f.Mode(), fpath, outdir)
if nil != err {
return err
}
if f.FileInfo().IsDir() {
continue
}
// this is actually function scope (not loop scope)
defer out.Close()
zf, err := f.Open()
if nil != err {
return err
}
defer zf.Close()
_, err = io.Copy(out, zf)
if nil != err {
return err
}
// close explicitly within loop scope
err = out.Close()
if nil != err {
return err
}
err = zf.Close()
if nil != err {
return err
}
}
return nil
}
func stripPrefix(fpath string, strip int) string {
// /foo/bar/baz/ => foo/bar/baz
// strip 1 => bar/baz
fpath = strings.Trim(filepath.ToSlash(fpath), "/")
parts := []string{}
if "" != fpath {
parts = strings.Split(fpath, "/")
}
if strip > 0 {
n := len(parts)
if strip > n {
strip = n
}
if 0 != len(parts) {
parts = parts[strip:]
}
}
return strings.Join(parts, "/")
}
// given the path return a file, tell that it's a directory, or error out
func safeOpen(fi os.FileInfo, fm os.FileMode, fpath string, outdir string) (io.WriteCloser, error) {
// Keep it clean
// https://github.com/snyk/zip-slip-vulnerability
cleanpath, _ := filepath.Abs(filepath.Clean(fpath))
cleandest, _ := filepath.Abs(filepath.Clean(outdir))
// foo/ foo => foo// foo/
// foo/ foo/bar.md => foo// foo/bar.md/
if !strings.HasPrefix(cleanpath+string(os.PathSeparator), cleandest+string(os.PathSeparator)) {
return nil, fmt.Errorf("Malicious file path: %s", fpath)
}
fpath = cleanpath
if fi.IsDir() {
err := os.MkdirAll(fpath, fm)
if nil != err {
return nil, err
}
return nil, err
}
if err := os.MkdirAll(filepath.Dir(fpath), 0755); nil != err {
return nil, err
}
out, err := os.OpenFile(fpath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, fm)
if nil != err {
return nil, err
}
return out, nil
}
// simpler to tar and untar than to have separate code to copy and to tar
func tarDir(tw *tar.Writer, src string, fis []os.FileInfo, trim string) error {
//fmt.Println("tarDir:", src)
for i := range fis {
fi := fis[i]
//fmt.Println("tarEntry:", src)
if err := tarEntry(tw, src, fi, trim); nil != err {
return err
}
}
return nil
}
func tarEntry(tw *tar.Writer, src string, fi os.FileInfo, trim string) error {
// gotta get perms
/*
stat, ok := info.Sys().(*syscall.Stat_t)
if !ok {
return fmt.Errorf("syscall failed for %q", src)
}
// TODO uid, username
Uid: int(stat.Uid),
Gid: int(stat.Gid),
*/
src = filepath.Join(src, fi.Name())
entryName := strings.TrimPrefix(strings.TrimPrefix(src, trim), "/")
switch fi.Mode() & os.ModeType {
case os.ModeSymlink:
//fmt.Println("tarSym:", src)
// TODO make sure that this is within the directory
targetpath, err := os.Readlink(src)
if nil != err {
return err
}
h, err := tar.FileInfoHeader(fi, targetpath)
if nil != err {
return err
}
h.Name = entryName
err = tw.WriteHeader(h)
if nil != err {
return err
}
// return to skip chmod
return nil
case os.ModeDir:
// directories must end in / for go
h, err := tar.FileInfoHeader(fi, "")
if nil != err {
return err
}
h.Name = entryName
h.Name = strings.TrimPrefix(h.Name+"/", "/")
//fmt.Printf("tarIsDir: %q %q\n", src, h.Name)
if "" != h.Name {
if err := tw.WriteHeader(h); nil != err {
return err
}
}
//fmt.Println("tarReadDir:", src)
fis, err := ioutil.ReadDir(src)
if nil != err {
return err
}
return tarDir(tw, src, fis, trim)
default:
//fmt.Println("tarDefault:", src)
if !fi.Mode().IsRegular() {
return fmt.Errorf("Unsupported file type: %s", src)
}
h, err := tar.FileInfoHeader(fi, "")
if nil != err {
return err
}
h.Name = entryName
if err := tw.WriteHeader(h); nil != err {
return err
}
r, err := os.Open(src)
defer r.Close()
if nil != err {
return err
}
if _, err := io.Copy(tw, r); nil != err {
return err
}
}
return nil
}
// Zip walks `src`, omitting `trim`, writing to `w`
func Zip(w io.Writer, src string, trim string) error {
zw := zip.NewWriter(w)
defer zw.Close()
return filepath.Walk(src, func(path string, fi os.FileInfo, err error) error {
// path includes fi.Name() already
if nil != err {
fmt.Println("warning: skipped", path+": ", err)
return nil
}
zipOne(zw, path, fi, trim)
return nil
})
}
func zipOne(zw *zip.Writer, path string, fi os.FileInfo, trim string) error {
h, err := zip.FileInfoHeader(fi)
if nil != err {
return err
}
h.Name = strings.TrimPrefix(strings.TrimPrefix(path, trim), string(filepath.Separator))
if fi.IsDir() {
//fmt.Printf("directory: %s\n\t%q\n", path, h.Name)
return zipDirectory(zw, h)
}
// Allow zipping a single file
if "" == h.Name {
h.Name = path
}
if fi.Mode().IsRegular() {
//fmt.Printf("file: %s\n\t%q\n", path, h.Name)
return zipFile(zw, h, path)
}
if os.ModeSymlink == (fi.Mode() & os.ModeType) {
//fmt.Printf("symlink: %s\n\t%q\n", path, h.Name)
return zipSymlink(zw, h, path)
}
fmt.Fprintf(os.Stderr, "skipping: %s\n\t(irregular file type)\n", path)
return nil
}
func zipDirectory(zw *zip.Writer, h *zip.FileHeader) error {
// directories must end in / for go
h.Name = strings.TrimPrefix(h.Name+"/", "/")
// skip top-level, trimmed directory
if "" == h.Name {
return nil
}
if _, err := zw.CreateHeader(h); nil != err {
return err
}
return nil
}
func zipFile(zw *zip.Writer, h *zip.FileHeader, path string) error {
r, err := os.Open(path)
if nil != err {
return err
}
defer r.Close()
// Files should be zipped (not dirs, and symlinks... meh)
// TODO investigate if files below a certain size shouldn't be deflated
h.Method = zip.Deflate
w, err := zw.CreateHeader(h)
if nil != err {
return err
}
if _, err := io.Copy(w, r); nil != err {
return err
}
return nil
}
func zipSymlink(zw *zip.Writer, h *zip.FileHeader, path string) error {
w, err := zw.CreateHeader(h)
if nil != err {
return err
}
// TODO make sure that this is within the root directory
targetpath, err := os.Readlink(path)
if nil != err {
return err
}
if _, err := w.Write([]byte(targetpath)); nil != err {
return err
}
return nil
}

799
package-lock.json

@ -0,0 +1,799 @@
{
"name": "telebit",
"version": "0.20.8",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@root/mkdirp": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@root/mkdirp/-/mkdirp-1.0.0.tgz",
"integrity": "sha512-hxGAYUx5029VggfG+U9naAhQkoMSXtOeXtbql97m3Hi6/sQSRL/4khKZPyOF6w11glyCOU38WCNLu9nUcSjOfA=="
},
"@root/request": {
"version": "1.3.11",
"resolved": "https://registry.npmjs.org/@root/request/-/request-1.3.11.tgz",
"integrity": "sha512-3a4Eeghcjsfe6zh7EJ+ni1l8OK9Fz2wL1OjP4UCa0YdvtH39kdXB9RGWuzyNv7dZi0+Ffkc83KfH0WbPMiuJFw=="
},
"accepts": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz",
"integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=",
"requires": {
"mime-types": "~2.1.18",
"negotiator": "0.6.1"
}
},
"acme": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/acme/-/acme-1.3.0.tgz",
"integrity": "sha512-Ny8aXnGdtlEVBZLpzNyVp7gff/3zFYrbfbiY93lx5jdrG4BrraA6P8RkRFP7NbFwh1rBgQkdHEsMxTp3f2r8dA==",
"requires": {
"acme-v2": "^1.6.0"
}
},
"acme-dns-01-cli": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/acme-dns-01-cli/-/acme-dns-01-cli-3.0.7.tgz",
"integrity": "sha512-Aa4bUpq6ftX1VODiShOetOY5U0tsXY5EV7+fQwme3Q8Y9rjYBArBXHgFCAVKtK1AF+Ev8pIuF6Z42hzMFa73/w=="
},
"acme-v2": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/acme-v2/-/acme-v2-1.8.2.tgz",
"integrity": "sha512-uYGA+DuTnA44EsGXE413XnbTotGHCzkucXjMk23QRwGnaGlnr0lNBoYjByyeIVLSzj0W6Y9FqA9h+15+H+ltMw==",
"requires": {
"@root/request": "^1.3.11",
"rsa-compat": "^2.0.8"
},
"dependencies": {
"@root/request": {
"version": "1.3.11",
"resolved": "https://registry.npmjs.org/@root/request/-/request-1.3.11.tgz",
"integrity": "sha512-3a4Eeghcjsfe6zh7EJ+ni1l8OK9Fz2wL1OjP4UCa0YdvtH39kdXB9RGWuzyNv7dZi0+Ffkc83KfH0WbPMiuJFw=="
}
}
},
"argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"requires": {
"sprintf-js": "~1.0.2"
}
},
"async-limiter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
},
"batch": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
"integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY="
},
"bluebird": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
"integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
},
"buffer-alloc": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
"integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
"requires": {
"buffer-alloc-unsafe": "^1.1.0",
"buffer-fill": "^1.0.0"
}
},
"buffer-alloc-unsafe": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
"integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg=="
},
"buffer-equal-constant-time": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
"integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
},
"buffer-fill": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
"integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw="
},
"buffer-from": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz",
"integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ=="
},
"cert-info": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/cert-info/-/cert-info-1.5.1.tgz",
"integrity": "sha512-eoQC/yAgW3gKTKxjzyClvi+UzuY97YCjcl+lSqbsGIy7HeGaWxCPOQFivhUYm27hgsBMhsJJFya3kGvK6PMIcQ=="
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"csv-parser": {
"version": "1.12.1",
"resolved": "https://registry.npmjs.org/csv-parser/-/csv-parser-1.12.1.tgz",
"integrity": "sha512-r45M92nLnGP246ot0Yo5RvbiiMF5Bw/OTIdWJ3OQ4Vbv4hpOeoXVIPxdSmUw+fPJlQOseY+iigJyLSfPMIrddQ==",
"requires": {
"buffer-alloc": "^1.1.0",
"buffer-from": "^1.0.0",
"generate-function": "^1.0.1",
"generate-object-property": "^1.0.0",
"inherits": "^2.0.1",
"minimist": "^1.2.0",
"ndjson": "^1.4.0"
},
"dependencies": {
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
}
}
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
},
"destroy": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
"ecdsa-sig-formatter": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
"requires": {
"safe-buffer": "^5.0.1"
}
},
"eckles": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/eckles/-/eckles-1.4.1.tgz",
"integrity": "sha512-auWyk/k8oSkVHaD4RxkPadKsLUcIwKgr/h8F7UZEueFDBO7BsE4y+H6IMUDbfqKIFPg/9MxV6KcBdJCmVVcxSA=="
},
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
},
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
},
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
},
"etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
},
"finalhandler": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
"integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==",
"requires": {
"debug": "2.6.9",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"on-finished": "~2.3.0",
"parseurl": "~1.3.2",
"statuses": "~1.4.0",
"unpipe": "~1.0.0"
}
},
"fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
"from2": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz",
"integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=",
"requires": {
"inherits": "^2.0.1",
"readable-stream": "^2.0.0"
}
},
"generate-function": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-1.1.0.tgz",
"integrity": "sha1-VMIbCAGSsW2Yd3ecW7gWZudyNl8="
},
"generate-object-property": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
"integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=",
"requires": {
"is-property": "^1.0.0"
}
},
"get-stream": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz",
"integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=",
"requires": {
"object-assign": "^4.0.1",
"pinkie-promise": "^2.0.0"
}
},
"greenlock": {
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/greenlock/-/greenlock-2.8.2.tgz",
"integrity": "sha512-pCAYjgVova1ZoUHhuCfIw/3Rs5tE6DK1YF2LI7Cyh15QFBZJNU7pngMvDfeFft3It4WqnHezNgyDWAeV2pWFaw==",
"requires": {
"acme": "^1.3.0",
"acme-dns-01-cli": "^3.0.0",
"acme-v2": "^1.8.1",
"cert-info": "^1.5.1",
"greenlock-store-fs": "^3.0.2",
"keypairs": "^1.2.14",
"le-challenge-fs": "^2.0.2",
"le-sni-auto": "^2.1.9",
"le-store-certbot": "^2.2.3",
"rsa-compat": "^2.0.8"
}
},
"greenlock-store-fs": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/greenlock-store-fs/-/greenlock-store-fs-3.0.2.tgz",
"integrity": "sha512-t4So75yKs1+7TqmxD5UKdf+zOQU0/4o0lb2auf5zUcAo7fwwNLOAXyWnnZRL3WuFBUiBGh1qXWleuMua0d3LPg==",
"requires": {
"@root/mkdirp": "^1.0.0",
"safe-replace": "^1.1.0"
}
},
"http-errors": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
"integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
"requires": {
"depd": "~1.1.2",
"inherits": "2.0.3",
"setprototypeof": "1.1.0",
"statuses": ">= 1.4.0 < 2"
}
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"into-stream": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/into-stream/-/into-stream-2.0.1.tgz",
"integrity": "sha1-25sANpRFPq4JHYpchMwRUHt4HTE=",
"requires": {
"from2": "^2.1.1"
}
},
"is-property": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
"integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"js-yaml": {
"version": "3.13.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
"integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
"requires": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
}
},
"json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
},
"jsonwebtoken": {
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
"integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
"requires": {
"jws": "^3.2.2",
"lodash.includes": "^4.3.0",
"lodash.isboolean": "^3.0.3",
"lodash.isinteger": "^4.0.4",
"lodash.isnumber": "^3.0.3",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.once": "^4.0.0",
"ms": "^2.1.1",
"semver": "^5.6.0"
},
"dependencies": {
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}
}
},
"jwa": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
"requires": {
"buffer-equal-constant-time": "1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"jws": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
"requires": {
"jwa": "^1.4.1",
"safe-buffer": "^5.0.1"
}
},
"keypairs": {
"version": "1.2.14",
"resolved": "https://registry.npmjs.org/keypairs/-/keypairs-1.2.14.tgz",
"integrity": "sha512-ZoZfZMygyB0QcjSlz7Rh6wT2CJasYEHBPETtmHZEfxuJd7bnsOG5AdtPZqHZBT+hoHvuWCp/4y8VmvTvH0Y9uA==",
"requires": {
"eckles": "^1.4.1",
"rasha": "^1.2.4"
}
},
"le-challenge-fs": {
"version": "2.0.9",
"resolved": "https://registry.npmjs.org/le-challenge-fs/-/le-challenge-fs-2.0.9.tgz",
"integrity": "sha512-stzI6rxd+aXGxBl87QJKKY/i/wl3uz6EoWzX2xSazJvCPSYBQys1RVNgOcf0SfUQPh6TBCFJFSJkiR4mznb4sg==",
"requires": {
"@root/mkdirp": "^1.0.0"
}
},
"le-sni-auto": {
"version": "2.1.9",
"resolved": "https://registry.npmjs.org/le-sni-auto/-/le-sni-auto-2.1.9.tgz",
"integrity": "sha512-QmQHNwQDi/56GY8+qczFZ06FZbxaeJQjbjEhwwQHhkJ9IHhIQFkPfCT/OyDfLj4gqLIrg5ZX8CemxxVZnLEYfg=="
},
"le-store-certbot": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/le-store-certbot/-/le-store-certbot-2.2.3.tgz",
"integrity": "sha512-c4ACR+v+JKMiAOOshLh6gdCKA7wIWR16+mROMLpQjq3rXJ3Vm8FaBHe2H+crT+flP+g7FmciAwUlfOJEJpIuCQ==",
"requires": {
"@root/mkdirp": "^1.0.0",
"pyconf": "^1.1.7",
"safe-replace": "^1.1.0"
}
},
"lodash.includes": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
"integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8="
},
"lodash.isboolean": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
"integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
},
"lodash.isinteger": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
"integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M="
},
"lodash.isnumber": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
"integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
},
"lodash.isplainobject": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
"integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
},
"lodash.isstring": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
"integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
},
"lodash.once": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
"integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
},
"mime": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
"integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ=="
},
"mime-db": {
"version": "1.33.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz",
"integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ=="
},
"mime-types": {
"version": "2.1.18",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz",
"integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==",
"requires": {
"mime-db": "~1.33.0"
}
},
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"requires": {
"minimist": "0.0.8"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"ndjson": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/ndjson/-/ndjson-1.5.0.tgz",
"integrity": "sha1-rmA7NrE0vOw0e0UkIrC/mNWDLsg=",
"requires": {
"json-stringify-safe": "^5.0.1",
"minimist": "^1.2.0",
"split2": "^2.1.0",
"through2": "^2.0.3"
},
"dependencies": {
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
}
}
},
"neat-csv": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/neat-csv/-/neat-csv-2.1.0.tgz",
"integrity": "sha1-BvWDYMTDuVW9Rn3cha5FEaOQekw=",
"requires": {
"csv-parser": "^1.6.0",
"get-stream": "^2.1.0",
"into-stream": "^2.0.0"
}
},
"negotiator": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
"integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"on-finished": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
"requires": {
"ee-first": "1.1.1"
}
},
"parseurl": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
"integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
},
"pify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY="
},
"pinkie": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
"integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA="
},
"pinkie-promise": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
"integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
"requires": {
"pinkie": "^2.0.0"
}
},
"process-nextick-args": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
},
"proxy-packer": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/proxy-packer/-/proxy-packer-2.0.2.tgz",
"integrity": "sha512-EQxdOMAYc8zINq9MsV7Vm55hjuNo4eC9z6GlqizCkeE5HldvnOCjsYJnwul+feey6RAJzp34klkD+9+0h2sXLQ=="
},
"ps-list": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ps-list/-/ps-list-5.0.0.tgz",
"integrity": "sha512-EnMjo990nDlzBVoV/m2Vo2+Ja3sO1Ikgo3TcLF2KI1DVW3SYEt8zouS40X4Z/tfULam5R3ig8a/rhmvE3mRq5w==",
"requires": {
"pify": "^3.0.0",
"tasklist": "^3.1.0"
}
},
"pyconf": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/pyconf/-/pyconf-1.1.7.tgz",
"integrity": "sha512-v4clh33m68sjtMsh8XMpjhGWb/MQODAYZ1y7ORG5Qv58UK25OddoB+oXyexgDkK8ttFui/lZm2sQDgA2Ftjfkw==",
"requires": {
"safe-replace": "^1.0.2"
}
},
"range-parser": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
"integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
},
"rasha": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/rasha/-/rasha-1.2.5.tgz",
"integrity": "sha512-KxtX+/fBk+wM7O3CNgwjSh5elwFilLvqWajhr6wFr2Hd63JnKTTi43Tw+Jb1hxJQWOwoya+NZWR2xztn3hCrTw=="
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"recase": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/recase/-/recase-1.0.4.tgz",
"integrity": "sha1-asoF8GFV5u0bY2LmIQUKEdvZ+FE="
},
"redirect-https": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/redirect-https/-/redirect-https-1.1.5.tgz",
"integrity": "sha512-40okBDSPOoK3E8ttlKxG60vBJMmxT+UPS43zrIkWo6QlNrRgvj/jY/trvATXpCN4XpuySdYsQnXxgfB8QBsBHg==",
"requires": {
"escape-html": "^1.0.3"
}
},
"rsa-compat": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/rsa-compat/-/rsa-compat-2.0.8.tgz",
"integrity": "sha512-BFiiSEbuxzsVdaxpejbxfX07qs+rtous49Y6mL/zw6YHh9cranDvm2BvBmqT3rso84IsxNlP5BXnuNvm1Wn3Tw==",
"requires": {
"keypairs": "^1.2.14"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"safe-replace": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/safe-replace/-/safe-replace-1.1.0.tgz",
"integrity": "sha512-9/V2E0CDsKs9DWOOwJH7jYpSl9S3N05uyevNjvsnDauBqRowBPOyot1fIvV5N2IuZAbYyvrTXrYFVG0RZInfFw=="
},
"sclient": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/sclient/-/sclient-1.4.1.tgz",
"integrity": "sha512-IsSIlWg9MjqknF3YtT6+ewCszAUeZfwLu2bNLSzbqoduc6t73K+zs/L2L5wmmgDL6BapBxqgwqBBchhizxS0JA=="
},
"sec": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/sec/-/sec-1.0.0.tgz",
"integrity": "sha1-Az1go60g7PLgCUDRT5eCNGV3QzU="
},
"semver": {
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA=="
},
"send": {
"version": "0.16.2",
"resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz",
"integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==",
"requires": {
"debug": "2.6.9",
"depd": "~1.1.2",
"destroy": "~1.0.4",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
"http-errors": "~1.6.2",
"mime": "1.4.1",
"ms": "2.0.0",
"on-finished": "~2.3.0",
"range-parser": "~1.2.0",
"statuses": "~1.4.0"
}
},
"serve-index": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
"integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=",
"requires": {
"accepts": "~1.3.4",
"batch": "0.6.1",
"debug": "2.6.9",
"escape-html": "~1.0.3",
"http-errors": "~1.6.2",
"mime-types": "~2.1.17",
"parseurl": "~1.3.2"
}
},
"serve-static": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz",
"integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==",
"requires": {
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"parseurl": "~1.3.2",
"send": "0.16.2"
}
},
"serve-tpl-attachment": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/serve-tpl-attachment/-/serve-tpl-attachment-1.0.4.tgz",
"integrity": "sha512-lv0t/G/x/Ikk780y+RChulnp42Q3xWStmgU4Yz2HXzO2uE+vJXfG7ntAzffgpuJSY29/arbAaqfEuI/NI5hNnA==",
"requires": {
"accepts": "^1.3.5",
"batch": "^0.6.1",
"mime-types": "^2.1.19"
},
"dependencies": {
"mime-db": {
"version": "1.35.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz",
"integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg=="
},
"mime-types": {
"version": "2.1.19",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz",
"integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==",
"requires": {
"mime-db": "~1.35.0"
}
}
}
},
"setprototypeof": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
"integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
},
"sni": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/sni/-/sni-1.0.0.tgz",
"integrity": "sha1-b6Qr35d23i43zsYBIua+yD3wBvU="
},
"socket-pair": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/socket-pair/-/socket-pair-1.0.4.tgz",
"integrity": "sha512-OEjlBOVBZpGBDvcjyYwFLZLGwNc8yMewKMirtoaR1WnX/XI2jo8ylsCEH4C6eXmcj5blQisECacN7yc3xlrwAA==",
"requires": {
"bluebird": "^3.5.1"
}
},
"split2": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz",
"integrity": "sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw==",
"requires": {
"through2": "^2.0.2"
}
},
"sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
},
"statuses": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
"integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew=="
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
},
"tasklist": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/tasklist/-/tasklist-3.1.0.tgz",
"integrity": "sha1-hzqYpORcvez6LC7hiGU1MFfmNpY=",
"requires": {
"neat-csv": "^2.1.0",
"pify": "^2.2.0",
"sec": "^1.0.0"
},
"dependencies": {
"pify": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
}
}
},
"through2": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
"integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=",
"requires": {
"readable-stream": "^2.1.5",
"xtend": "~4.0.1"
}
},
"toml": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/toml/-/toml-0.4.1.tgz",
"integrity": "sha1-Iv5QHFe+WpV9o4JcHd5YS7LmL3M="
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"ws": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-6.0.0.tgz",
"integrity": "sha512-c2UlYcAZp1VS8AORtpq6y4RJIkJ9dQz18W32SpR/qXGfLDZ2jU4y4wKvvZwqbi7U6gxFQTeE+urMbXU/tsDy4w==",
"requires": {
"async-limiter": "~1.0.0"
}
},
"xtend": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
}
}
}

6
package.json

@ -13,6 +13,8 @@
"telebitd": "bin/telebitd.js"
},
"scripts": {
"preinstall": "node scripts/preinstall.js",
"postinstall": "node scripts/postinstall.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
@ -55,9 +57,9 @@
"dependencies": {
"@coolaj86/urequest": "^1.3.5",
"finalhandler": "^1.1.1",
"greenlock": "^2.3.1",
"greenlock": "^2.8.2",
"js-yaml": "^3.11.0",
"jsonwebtoken": "^7.1.9",
"jsonwebtoken": "^8.5.1",
"mkdirp": "^0.5.1",
"proxy-packer": "^2.0.2",
"ps-list": "^5.0.0",

50
scripts/postinstall.js

@ -0,0 +1,50 @@
'use strict';
// use pathman and serviceman to make telebit ready
var spawn = require('child_process').spawn;
var os = require('os');
var path = require('path');
var ext = /^win/i.test(os.platform()) ? '.exe' : '';
function run(bin, args) {
return new Promise(function(resolve, reject) {
var runner = spawn(path.join(bin + ext), args, {
windowsHide: true
});
runner.stdout.on('data', function(chunk) {
console.info(chunk.toString('utf8'));
});
runner.stderr.on('data', function(chunk) {
console.error(chunk.toString('utf8'));
});
runner.on('exit', function(code) {
if (0 !== code) {
reject(
new Error("exited with non-zero status code '" + code + "'")
);
return;
}
resolve({ code: code });
});
});
}
run('serviceman', [
'add',
'--name',
'telebit',
'--title',
'Telebit',
'--rdns',
'io.telebit.remote.telebit',
path.resolve(__dirname, '..', 'bin', 'telebit.js'),
'--',
'daemon',
'--config',
path.join(os.homedir(), '.config/telebit/telebitd.yml')
])
.then(function() {})
.catch(function(e) {
console.error(e.message);
});

53
scripts/preinstall.js

@ -0,0 +1,53 @@
'use strict';
// use pathman and serviceman to make telebit ready
var spawn = require('child_process').spawn;
var os = require('os');
var path = require('path');
var ext = /^win/i.test(os.platform()) ? '.exe' : '';
function run(bin, args) {
return new Promise(function(resolve, reject) {
var runner = spawn(path.join(bin + ext), args, {
windowsHide: true
});
var out = '';
runner.stdout.on('data', function(chunk) {
var txt = chunk.toString('utf8');
out += txt;
});
runner.stderr.on('data', function(chunk) {
var txt = chunk.toString('utf8');
out += txt;
});
runner.on('exit', function(code) {
if (
0 !== code &&
!/service matching/.test(out) &&
!/no pid file/.test(out)
) {
console.error(out);
reject(
new Error("exited with non-zero status code '" + code + "'")
);
return;
}
resolve({ code: code });
});
});
}
var confpath = path.join(os.homedir(), '.config/telebit');
require('mkdirp')(confpath, function(err) {
if (err) {
console.error("Error creating config path '" + confpath + "':");
console.error(err);
}
// not having a config is fine
});
run('serviceman', ['stop', 'telebit']).catch(function(e) {
// TODO ignore
console.error(e.message);
});

61
usr/share/dist/Library/LaunchDaemons/cloud.telebit.remote.plist.tpl

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>Telebit Remote</string>
<key>ProgramArguments</key>
<array>
<string>{TELEBIT_NODE}</string>
<string>{TELEBITD_JS}</string>
<string>daemon</string>
<string>--config</string>
<string>{TELEBITD_CONFIG}</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>TELEBIT_PATH</key>
<string>{TELEBIT_PATH}</string>
<key>NODE_PATH</key>
<string>{NODE_PATH}</string>
<key>NPM_CONFIG_PREFIX</key>
<string>{NPM_CONFIG_PREFIX}</string>
</dict>
<key>UserName</key>
<string>{TELEBIT_USER}</string>
<key>GroupName</key>
<string>{TELEBIT_GROUP}</string>
<key>InitGroups</key>
<true/>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<!--dict>
<key>Crashed</key>
<true/>
<key>NetworkState</key>
<true/>
<key>SuccessfulExit</key>
<false/>
</dict-->
<key>SoftResourceLimits</key>
<dict>
<key>NumberOfFiles</key>
<integer>8192</integer>
</dict>
<key>HardResourceLimits</key>
<dict/>
<key>WorkingDirectory</key>
<string>{TELEBIT_PATH}</string>
<key>StandardErrorPath</key>
<string>{TELEBIT_LOG_DIR}/telebit.log</string>
<key>StandardOutPath</key>
<string>{TELEBIT_LOG_DIR}/telebit.log</string>
</dict>
</plist>

2
usr/share/dist/bin/telebit.tpl

@ -1,2 +0,0 @@
#!/bin/bash
{TELEBIT_NODE} {TELEBIT_JS} "$@"

2
usr/share/dist/bin/telebitd.tpl

@ -1,2 +0,0 @@
#!/bin/bash
{TELEBIT_NODE} {TELEBITD_JS} daemon "$@"

64
usr/share/dist/etc/skel/.config/systemd/user/telebit.service.tpl

@ -1,64 +0,0 @@
# Pre-req
# sudo adduser telebit --home {TELEBIT_PATH}
# sudo mkdir -p {TELEBIT_PATH}/
# sudo chown -R {TELEBIT_USER}:{TELEBIT_GROUP} {TELEBIT_PATH}/
[Unit]
Description=Telebit Remote
Documentation=https://git.coolaj86.com/coolaj86/telebit.js/
; After=network-online.target
; Wants=network-online.target systemd-networkd-wait-online.service
[Service]
# Restart on crash (bad signal), and also on 'clean' failure (error exit code)
# Allow up to 3 restarts within 10 seconds
# (it's unlikely that a user or properly-running script will do this)
Restart=always
StartLimitInterval=10
StartLimitBurst=3
# User and group the process will run as
;User={TELEBIT_USER}
;Group={TELEBIT_GROUP}
WorkingDirectory={TELEBIT_PATH}
# custom directory cannot be set and will be the place where this exists, not the working directory
ExecStart={TELEBIT_NODE} {TELEBITD_JS} daemon --config {TELEBITD_CONFIG}
ExecReload=/bin/kill -USR1 $MAINPID
# Limit the number of file descriptors and processes; see `man systemd.exec` for more limit settings.
# Unmodified, this is not expected to use more than this.
;LimitNOFILE=1048576 # no issues yet, but disabled just in case
;LimitNPROC=64 # doesn't work on some systems
# Use private /tmp and /var/tmp, which are discarded after this stops.
PrivateTmp=true
# Use a minimal /dev
;PrivateDevices=true
# Hide /home, /root, and /run/user. Nobody will steal your SSH-keys.
ProtectHome=true
# Make /usr, /boot, /etc and possibly some more folders read-only.
ProtectSystem=full
# ... except for a few because we want a place for config, logs, etc
# This merely retains r/w access rights, it does not add any new.
# Must still be writable on the host!
ReadWriteDirectories={TELEBIT_RW_DIRS}
# Note: in v231 and above ReadWritePaths has been renamed to ReadWriteDirectories
; ReadWritePaths={TELEBIT_RW_DIRS}
# The following additional security directives only work with systemd v229 or later.
# They further retrict privileges that can be gained.
# Note that you may have to add capabilities required by any plugins in use.
;CapabilityBoundingSet=CAP_NET_BIND_SERVICE
;AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=true
# Caveat: Some features may need additional capabilities.
# For example an "upload" may need CAP_LEASE
; CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_LEASE
; AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_LEASE
; NoNewPrivileges=true
[Install]
WantedBy=multi-user.target

70
usr/share/dist/etc/skel/Library/LaunchAgents/cloud.telebit.remote.plist.tpl

@ -1,70 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>Telebit Remote</string>
<key>ProgramArguments</key>
<array>
<string>{TELEBIT_NODE}</string>
<string>{TELEBITD_JS}</string>
<string>daemon</string>
<string>--config</string>
<string>{TELEBITD_CONFIG}</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>TELEBIT_PATH</key>
<string>{TELEBIT_PATH}</string>
<key>NODE_PATH</key>
<string>{NODE_PATH}</string>
<key>NPM_CONFIG_PREFIX</key>
<string>{NPM_CONFIG_PREFIX}</string>
</dict>
<!--
:: LaunchDaemon Only ::
<key>UserName</key>
<string>{TELEBIT_USER}</string>
<key>GroupName</key>
<string>{TELEBIT_GROUP}</string>
<key>InitGroups</key>
<true/>
-->
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<!--
<dict>
<key>Crashed</key>
<true/>
<key>NetworkState</key>
<true/>
<key>SuccessfulExit</key>
<false/>
</dict>
-->
<!--
<key>SoftResourceLimits</key>
<dict>
<key>NumberOfFiles</key>
<integer>8192</integer>
</dict>
<key>HardResourceLimits</key>
<dict/>
-->
<key>WorkingDirectory</key>
<string>{TELEBIT_PATH}</string>
<key>StandardErrorPath</key>
<string>{TELEBIT_LOG_DIR}/telebit.log</string>
<key>StandardOutPath</key>
<string>{TELEBIT_LOG_DIR}/telebit.log</string>
</dict>
</plist>

67
usr/share/dist/etc/systemd/system/telebit.service.tpl

@ -1,67 +0,0 @@
# Pre-req
# sudo adduser telebit --home {TELEBIT_PATH}
# sudo mkdir -p {TELEBIT_PATH}/
# sudo chown -R {TELEBIT_USER}:{TELEBIT_GROUP} {TELEBIT_PATH}/
[Unit]
Description=Telebit Remote
Documentation=https://git.coolaj86.com/coolaj86/telebit.js/
After=network-online.target
Wants=network-online.target systemd-networkd-wait-online.service
[Service]
# Restart on crash (bad signal), and also on 'clean' failure (error exit code)
# Allow up to 3 restarts within 10 seconds
# (it's unlikely that a user or properly-running script will do this)
Restart=always
StartLimitInterval=10
StartLimitBurst=3
# User and group the process will run as
User={TELEBIT_USER}
Group={TELEBIT_GROUP}
WorkingDirectory={TELEBIT_PATH}
# custom directory cannot be set and will be the place where this exists, not the working directory
ExecStart={TELEBIT_NODE} {TELEBITD_JS} daemon --config {TELEBITD_CONFIG}
ExecReload=/bin/kill -USR1 $MAINPID
# Limit the number of file descriptors and processes; see `man systemd.exec` for more limit settings.
# Unmodified, this is not expected to use more than this.
LimitNOFILE=1048576
LimitNPROC=64
# Use private /tmp and /var/tmp, which are discarded after this stops.
PrivateTmp=true
# Use a minimal /dev
PrivateDevices=true
# Hide /home, /root, and /run/user. Nobody will steal your SSH-keys.
ProtectHome=true
# Make /usr, /boot, /etc and possibly some more folders read-only.
ProtectSystem=full
# ... except for a few because we want a place for config, logs, etc
# This merely retains r/w access rights, it does not add any new.
# Must still be writable on the host!
ReadWriteDirectories={TELEBIT_RW_DIRS}
# Note: in v231 and above ReadWritePaths has been renamed to ReadWriteDirectories
; ReadWritePaths={TELEBIT_RW_DIRS}
# The following additional security directives only work with systemd v229 or later.
# They further retrict privileges that can be gained.
# Note that you may have to add capabilities required by any plugins in use.
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
NoNewPrivileges=true
# Caveat: Some features may need additional capabilities.
# For example an "upload" may need CAP_LEASE
; CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_LEASE
; AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_LEASE
; NoNewPrivileges=true
[Install]
# For system-level service
;WantedBy=multi-user.target
# For userspace service
WantedBy=default.target

14
usr/share/gen-tab.sh

@ -0,0 +1,14 @@
# bash gen-tab.sh >> index.tab
#
# version major size sha256 channel os arch url
# v0.20.8 v0.20 25119710 4128ee6ef3dcc9c754dd1e46d1d68a217707017c223b417d34a6d0e56ab86f1a stable darwin amd64 https://rootprojects.org/telebit/dist/stable/telebit-stable-darwin-amd64.tar.gz
for x in stable/*; do
my_os="$(echo $x | cut -d '-' -f 3)"
my_arch="$(echo $x | cut -d '-' -f 4 | cut -d '.' -f 1)"
my_version="v0.20.8"
my_major="v0.20"
my_chan="stable"
my_sha256=$(sha256sum -b "$x" | cut -d ' ' -f 1)
my_size=$(ls -l "$x" | cut -d ' ' -f 5)
printf "${my_version}\t${my_major}\t${my_size}\t${my_sha256}\t${my_chan}\t${my_os}\t${my_arch}\thttps://rootprojects.org/telebit/dist/$x\n"
done

448
usr/share/install-launcher.js

@ -1,448 +0,0 @@
'use strict';
//var fs = require('fs');
var os = require('os');
var mkdirp = require('mkdirp');
var exec = require('child_process').exec;
var path = require('path');
var Launcher = module.exports;
Launcher._killAll = function (fn) {
var psList = require('ps-list');
psList().then(function (procs) {
procs.forEach(function (proc) {
if ('node' === proc.name && /\btelebitd\b/i.test(proc.cmd)) {
console.log(proc);
process.kill(proc.pid);
return true;
}
});
// Two things:
// 1) wait to see if the process dies
// 2) wait to give time for the socket to connect
setTimeout(function () {
if (fn) { fn(null); return; }
}, 1.75 * 1000);
});
};
Launcher._getError = function getError(err, stderr) {
if (err) { return err; }
if (stderr) {
err = new Error(stderr);
err.code = 'ELAUNCHER';
return err;
}
};
Launcher._detect = function (things, fn) {
if (things.launcher) {
if ('string' === typeof things.launcher) {
fn(null, things.launcher);
return;
}
if ('function' === typeof things.launcher) {
things.launcher(things);
return;
}
}
// could have used "command-exists" but I'm trying to stay low-dependency
// os.platform(), os.type()
if (!/^win/i.test(os.platform())) {
if (/^darwin/i.test(os.platform())) {
exec('command -v launchctl', things._execOpts, function (err, stdout, stderr) {
err = Launcher._getError(err, stderr);
fn(err, 'launchctl');
});
} else {
exec('command -v systemctl', things._execOpts, function (err, stdout, stderr) {
err = Launcher._getError(err, stderr);
fn(err, 'systemctl');
});
}
} else {
// https://stackoverflow.com/questions/17908789/how-to-add-an-item-to-registry-to-run-at-startup-without-uac
// wininit? regedit? SCM?
// REG ADD "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /V "My App" /t REG_SZ /F /D "C:\MyAppPath\MyApp.exe"
// https://www.microsoft.com/developerblog/2015/11/09/reading-and-writing-to-the-windows-registry-in-process-from-node-js/
// https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/reg-add
// https://social.msdn.microsoft.com/Forums/en-US/5b318f44-281e-4098-8dee-3ba8435fa391/add-registry-key-for-autostart-of-app-in-ice?forum=quebectools
// utils.elevate
// https://github.com/CatalystCode/windows-registry-node
exec('where reg.exe', things._execOpts, function (err, stdout, stderr) {
//console.log((stdout||'').trim());
if (stderr) {
console.error(stderr);
}
fn(err, 'reg.exe');
});
}
};
Launcher.install = function (things, fn) {
if (!fn) { fn = function (err) { if (err) { console.error(err); } }; }
things = things || {};
// in some future version we can take this file out
// and accept process.env from things
var installLauncher = require('./template-launcher');
// Right now this is just for npm install -g and npx
if (things.env) {
things.env.PATH = things.env.PATH || process.env.PATH;
} else {
things.env = process.env;
}
things.argv = things.argv || process.argv;
things._execOpts = { windowsHide: true, env: things.env };
var telebitRoot = path.join(__dirname, '../..');
var vars = {
telebitPath: telebitRoot
, telebitUser: os.userInfo().username
, telebitGroup: (/^darwin/i.test(os.platform()) ? 'staff' : os.userInfo().username)
, telebitRwDirs: [
telebitRoot
, path.join(os.homedir(), '.config/telebit')
, path.join(os.homedir(), '.local/share/telebit')
]
, telebitNode: (things.argv[0]||'').replace(/\.exe/i, '') // path.join(telebitRoot, 'bin/node')
, telebitBin: path.join(telebitRoot, 'bin/telebit')
, telebitdBin: path.join(telebitRoot, 'bin/telebitd')
, telebitJs: path.join(telebitRoot, 'bin/telebit.js')
, telebitdJs: path.join(telebitRoot, 'bin/telebitd.js')
, telebitConfig: path.join(os.homedir(), '.config/telebit/telebit.yml')
, telebitdConfig: path.join(os.homedir(), '.config/telebit/telebitd.yml')
, TELEBIT_LOG_DIR: path.join(os.homedir(), '.local/share/telebit/var/log')
, TELEBIT_SOCK_DIR: path.join(os.homedir(), '.local/share/telebit/var/run')
};
vars.telebitBinTpl = path.join(telebitRoot, 'usr/share/dist/bin/telebit.tpl');
vars.telebitNpm = path.resolve(vars.telebitNode, '../npm');
vars.nodePath = path.resolve(vars.telebitNode, '../../lib/node_modules');
vars.npmConfigPrefix = path.resolve(vars.telebitNode, '..', '..');
vars.userspace = (!things.telebitUser || (things.telebitUser === os.userInfo().username)) ? true : false;
if (-1 === vars.telebitRwDirs.indexOf(vars.npmConfigPrefix)) {
vars.telebitRwDirs.push(vars.npmConfigPrefix);
}
vars.telebitRwDirs = vars.telebitRwDirs.join(' ');
var launchers = {
'node': function () {
var fs = require('fs');
var spawn = require('child_process').spawn;
var logpath = path.join(os.homedir(), '.local/share/telebit/var/log');
try {
mkdirp.sync(logpath);
} catch(e) {
if (fn) { fn(e); return; }
return;
}
var stdout = fs.openSync(path.join(logpath, 'info.log'), 'a');
var stderr = fs.openSync(path.join(logpath, 'error.log'), 'a');
var killed = 0;
var err;
var args = [
path.join(telebitRoot, 'bin/telebitd.js')
, 'daemon'
, '--config'
, vars.telebitdConfig
];
var subprocess = spawn(
vars.telebitNode
, args
, { detached: true
, stdio: [ 'ignore', stdout, stderr ]
}
);
//console.log('[debug]', vars.telebitNode, args.join(' '));
subprocess.unref();
subprocess.on('error', function (_err) {
err = _err;
killed += 1;
});
subprocess.on('exit', function (code, signal) {
if (!err) { err = new Error('' + code + ' ' + signal + ' failure to launch'); }
killed += 1;
});
// Two things:
// 1) wait to see if the process dies
// 2) wait to give time for the socket to connect
setTimeout(function () {
if (fn) { fn(err); return; }
}, 1.75 * 1000);
return;
}
, 'launchctl': function () {
var launcher = path.join(os.homedir(), 'Library/LaunchAgents/cloud.telebit.remote.plist');
try {
mkdirp.sync(path.join(os.homedir(), 'Library/LaunchAgents'));
installLauncher.sync({
file: {
tpl: vars.telebitBinTpl
, launcher: path.join(vars.telebitPath, 'bin/telebit')
, executable: true
}
, vars: vars
});
installLauncher({
file: {
tpl: path.join(vars.telebitPath, 'usr/share/dist/etc/skel/Library/LaunchAgents/cloud.telebit.remote.plist.tpl')
, launcher: launcher
}
, vars: vars
});
var launcherstr = (vars.userspace ? "" : "sudo ") + "launchctl ";
var execstr = launcherstr + "unload -w " + launcher;
exec(execstr, things._execOpts, function (/*err, stdout, stderr*/) {
// we probably only need to skip the stderr (saying that it can't stop something that isn't started)
//err = Launcher._getError(err, stderr);
//if (err) { fn(err); return; }
//console.log((stdout||'').trim());
//console.log('unload worked?');
execstr = launcherstr + "load -w " + launcher;
exec(execstr, things._execOpts, function (err, stdout, stderr) {
err = Launcher._getError(err, stderr);
if (err) { fn(err); return; }
//console.log((stdout||'').trim());
//console.log('load worked?');
setTimeout(function () {
fn(null);
}, 1.25 * 1000);
});
});
} catch(e) {
console.error("'" + launcher + "' error:");
console.error(e);
if (fn) { fn(e); return; }
}
}
, 'systemctl': function () {
var launcher = path.join(os.homedir(), '.config/systemd/user/telebit.service');
var launchername = 'telebit.service';
try {
mkdirp.sync(path.join(os.homedir(), '.config/systemd/user'));
installLauncher({
file: {
tpl: path.join(vars.telebitPath, 'usr/share/dist/etc/skel/.config/systemd/user/telebit.service.tpl')
, launcher: launcher
}
, vars: vars
}, function () {
// IMPORTANT
// It's a dangerous to go alone, take this:
// SYSTEMD_LOG_LEVEL=debug journalctl -xef --user-unit=telebit
// (makes debugging systemd issues not "easy" per se, but possible)
var launcherstr = (vars.userspace ? "" : "sudo ") + "systemctl " + (vars.userspace ? "--user " : "");
var execstr = launcherstr + "daemon-reload";
exec(execstr, things._execOpts, function (err, stdout, stderr) {
err = Launcher._getError(err, stderr);
if (err) { fn(err); return; }
//console.log((stdout||'').trim());
var execstr = launcherstr + "enable " + launchername;
exec(execstr, things._execOpts, function (err, stdout, stderr) {
err = Launcher._getError(err, stderr && !/Created symlink/i.test(stderr) && stderr || '');
if (err) { fn(err); return; }
//console.log((stdout||'').trim());
var execstr = launcherstr + "restart " + launchername;
exec(execstr, things._execOpts, function (err, stdout, stderr) {
err = Launcher._getError(err, stderr);
if (err) { fn(err); return; }
//console.log((stdout||'').trim());
setTimeout(function () {
var execstr = launcherstr + "status " + launchername;
exec(execstr, things._execOpts, function (err, stdout, stderr) {
err = Launcher._getError(err, stderr);
if (err) { fn(err); return; }
if (!/active.*running/i.test(stdout)) {
err = new Error("systemd failed to start '" + launchername + "'");
}
if (err) { fn(err); return; }
//console.log((stdout||'').trim());
fn(null);
});
}, 1.25 * 1000);
});
});
});
});
} catch(e) {
console.error("'" + launcher + "' error:");
console.error(e);
if (fn) { fn(e); return; }
}
}
, 'reg.exe': function () {
if (!vars.userspace) {
console.warn("sysetm-level, privileged services are not yet supported on windows");
}
vars.telebitNode += '.exe';
var cmd = 'reg.exe add "HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"'
+ ' /V "Telebit" /t REG_SZ /D '
+ '"' + things.argv[0] + ' /c ' // something like C:\\Program Files (x64)\nodejs\node.exe
+ [ path.join(__dirname, 'bin/telebitd.js')
, 'daemon'
, '--config'
, path.join(os.homedir(), '.config/telebit/telebitd.yml')
].join(' ')
+ '" /F'
;
exec(cmd, things._execOpts, function (err, stdout, stderr) {
err = Launcher._getError(err, stderr);
if (err) { fn(err); return; }
// need to start it for the first time ourselves
run(null, 'node');
});
}
};
function run(err, launcher) {
if (err) {
console.error("No luck with '" + launcher + "', trying a child process instead...");
console.error(err);
launcher = 'node';
}
if (launchers[launcher]) {
// console.log('Launching with launcher ' + launcher);
mkdirp.sync(path.join(vars.telebitPath, 'bin'));
mkdirp.sync(vars.TELEBIT_LOG_DIR);
mkdirp.sync(vars.TELEBIT_SOCK_DIR);
launchers[launcher]();
return;
} else {
console.error("No launcher handler for '" + launcher+ "'");
}
}
things._vars = vars;
things._userspace = vars.userspace;
Launcher._detect(things, run);
};
Launcher.uninstall = function (things, fn) {
if (!fn) { fn = function (err) { if (err) { console.error(err); } }; }
things = things || {};
// Right now this is just for npm install -g and npx
if (things.env) {
things.env.PATH = things.env.PATH || process.env.PATH;
} else {
things.env = process.env;
}
things.argv = things.argv || process.argv;
things._execOpts = { windowsHide: true, env: things.env };
var vars = {
telebitUser: os.userInfo().username
};
vars.userspace = (!things.telebitUser || (things.telebitUser === os.userInfo().username)) ? true : false;
var launchers = {
'node': function () {
Launcher._killAll(fn);
}
, 'launchctl': function () {
var launcher = path.join(os.homedir(), 'Library/LaunchAgents/cloud.telebit.remote.plist');
try {
var launcherstr = (vars.userspace ? "" : "sudo ") + "launchctl ";
var execstr = launcherstr + "unload -w " + launcher;
exec(execstr, things._execOpts, function (err, stdout, stderr) {
// we probably only need to skip the stderr (saying that it can't stop something that isn't started)
//err = Launcher._getError(err, stderr);
//if (err) { fn(err); return; }
//console.log((stdout||'').trim());
//console.log('unload worked?');
err = Launcher._getError(err, stderr);
if (err) { fn(err); return; }
//console.log((stdout||'').trim());
//console.log('load worked?');
setTimeout(function () {
fn(null);
}, 1.25 * 1000);
});
} catch(e) {
console.error("'" + launcher + "' error (uninstall):");
console.error(e);
if (fn) { fn(e); return; }
}
}
, 'systemctl': function () {
var launcher = path.join(os.homedir(), '.config/systemd/user/telebit.service');
var launchername = 'telebit.service';
try {
mkdirp.sync(path.join(os.homedir(), '.config/systemd/user'));
// IMPORTANT
// It's a dangerous to go alone, take this:
// SYSTEMD_LOG_LEVEL=debug journalctl -xef --user-unit=telebit
// (makes debugging systemd issues not "easy" per se, but possible)
var launcherstr = (vars.userspace ? "" : "sudo ") + "systemctl " + (vars.userspace ? "--user " : "");
var execstr = launcherstr + "disable " + launchername;
exec(execstr, things._execOpts, function (err, stdout, stderr) {
err = Launcher._getError(err, stderr && !/Removed symlink/i.test(stderr) && stderr || '');
if (err) { fn(err); return; }
//console.log((stdout||'').trim());
var execstr = launcherstr + "stop " + launchername;
exec(execstr, things._execOpts, function (err, stdout, stderr) {
err = Launcher._getError(err, stderr);
if (err) { fn(err); return; }
//console.log((stdout||'').trim());
setTimeout(function () {
var execstr = launcherstr + "status " + launchername;
exec(execstr, things._execOpts, function (err, stdout, stderr) {
err = Launcher._getError(err, stderr);
if (err) { fn(err); return; }
if (!/inactive.*dead/i.test(stdout)) {
err = new Error("systemd failed to stop '" + launchername + "'");
}
if (err) { fn(err); return; }
//console.log((stdout||'').trim());
fn(null);
});
}, 1.25 * 1000);
});
});
} catch(e) {
console.error("'" + launcher + "' error:");
console.error(e);
if (fn) { fn(e); return; }
}
}
, 'reg.exe': function () {
if (!vars.userspace) {
console.warn("sysetm-level, privileged services are not yet supported on windows");
}
var cmd = 'reg.exe add "HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"'
+ ' /V "Telebit" /F'
;
exec(cmd, things._execOpts, function (err, stdout, stderr) {
err = Launcher._getError(err, stderr);
if (err) { fn(err); return; }
// need to start it for the first time ourselves
kill(null, 'node');
});
}
};
function kill(err, launcher) {
if (err) {
console.error("No luck with '" + launcher + "', trying a process.kill() instead...");
console.error(err);
launcher = 'node';
}
if (launchers[launcher]) {
launchers[launcher]();
return;
} else {
console.error("No launcher handler (uninstall) for '" + launcher + "'");
}
}
things._vars = vars;
things._userspace = vars.userspace;
Launcher._detect(things, kill);
};
if (module === require.main) {
Launcher.install({
argv: process.argv
, env: process.env
}, function (err) {
if (err) { console.error(err); return; }
console.log("Telebit launched, or so it seems.");
});
}

14
usr/share/install.cmd

@ -0,0 +1,14 @@
powershell.exe $ProgressPreference = 'SilentlyContinue'; Invoke-WebRequest https://rootprojects.org/telebit/dist/stable/telebit-stable-windows-amd64.zip -OutFile telebit.zip
mkdir %SYSTEMPROFILE%\.local\opt\
del /F /Q /S %SYSTEMPROFILE%\.local\opt\telebit-stable-windows-amd64 > NUL
rmdir /Q /S %SYSTEMPROFILE%\.local\opt\telebit-stable-windows-amd64
powershell.exe Expand-Archive -Force .\telebit.zip %SYSTEMPROFILE%\.local\opt\
%SYSTEMPROFILE%\.local\opt\telebit-stable-windows-amd64\bin\serviceman.exe stop telebit
del /F /Q /S %SYSTEMPROFILE%\.local\opt\telebit\* > NUL
rmdir /Q /S %SYSTEMPROFILE%\.local\opt\telebit
move %SYSTEMPROFILE%\.local\opt\telebit-stable-windows-amd64 %SYSTEMPROFILE%\.local\opt\telebit
%SYSTEMPROFILE%\.local\opt\telebit\bin\serviceman.exe add --name telebit %SYSTEMPROFILE%\.local\opt\telebit\bin\node %SYSTEMPROFILE%\.local\opt\telebit\bin\telebitd.js
%SYSTEMPROFILE%\.local\opt\telebit\bin\pathman.exe add %SYSTEMPROFILE%\.local\opt\telebit\bin

260
usr/share/install.sh

@ -45,7 +45,7 @@ detect_http_get()
_my_http_opts="--quiet"
_my_http_out="-O"
else
echo "Aborted, could not find curl or wget"
echo "Failed to find 'curl' or 'wget' to download setup files."
return 7
fi
set -e
@ -74,12 +74,258 @@ export -f http_bash
## END HTTP_GET ##
###############################
if [ -n "${TELEBIT_VERSION:-}" ]; then
echo 'TELEBIT_VERSION='${TELEBIT_VERSION}
# Priority
#darwin-x64 tar.gz 28-May-2019 21:25 17630540
#linux-arm64 tar.gz 28-May-2019 21:14 20114146
#linux-armv6l tar.gz 28-May-2019 21:19 19029391
#linux-armv7l tar.gz 28-May-2019 21:22 18890540
#linux-x64 tar.gz 28-May-2019 21:36 20149492
#win-x64 zip 28-May-2019 22:08 17455164
#win-x86 zip 28-May-2019 21:57 15957629
# TODO
#aix-ppc64 tar.gz 28-May-2019 21:45 24489408
#linux-ppc64le tar.gz 28-May-2019 21:18 20348655
#linux-s390x tar.gz 28-May-2019 21:19 20425501
#sunos-x64 tar.gz 28-May-2019 21:19 21382759
#... cygwin?
# Extra
#x64 msi 28-May-2019 22:09 18186240
#x86 msi 28-May-2019 21:57 16601088
#(darwin) pkg 28-May-2019 21:22 17869062
###############################
## PLATFORM DETECTION ##
###############################
echo "Detecting your system..."
sleep 0.5
echo ""
# OSTYPE https://stackoverflow.com/a/8597411/151312
my_os=''
my_os_friendly=''
my_arch=''
my_arch_friendly=''
if [ "$(uname | grep -i 'Darwin')" ]; then
#OSX_VER="$(sw_vers | grep ProductVersion | cut -d':' -f2 | cut -f2)"
#OSX_MAJOR="$(echo ${OSX_VER} | cut -d'.' -f1)"
my_os='darwin'
my_os_friendly='MacOS'
#if [ -n "$(sysctl hw | grep 64bit | grep ': 1')" ]; then
# my_arch="amd64"
#fi
my_unarchiver="tar"
elif [ "$(uname | grep -i 'MING')" ] || [[ "$OSTYPE" == "msys" ]]; then
my_os='windows'
# although it's not quite our market, many people don't know if they have "microsoft" OR "windows"
my_os_friendly='Microsoft Windows'
my_unarchiver="unzip"
elif [ "$(uname | grep -i 'Linux')" ] || [[ "$OSTYPE" == "linux-gnu" ]]; then
my_os='linux'
my_os_friendly='Linux'
# Find out which linux... but there are too many
#cat /etc/issue
my_unarchiver="tar"
else
>&2 echo "You don't appear to be on Mac (darwin), Linux, or Windows (mingw32)."
>&2 echo "Help us support your platform by filing an issue:"
>&2 echo " https://git.rootprojects.org/root/telebit.js/issues"
exit 1
fi
export TELEBIT_VERSION=${TELEBIT_VERSION:-master}
if [ -e "usr/share/install_helper.sh" ]; then
bash usr/share/install_helper.sh "$@"
export _my_unarchiver=""
export _my_unarchive_opts=""
export _my_unarchive_out=""
export archive_ext=""
detect_unarchiver()
{
set +e
if type -p "$my_unarchiver" >/dev/null 2>&1; then
if [ "tar" == "$my_unarchiver" ]; then
_my_unarchiver="tar"
_my_unarchive_opts="-xf"
_my_unarchive_out="-C"
archive_ext="tar.gz"
elif [ "unzip" == "$my_unarchiver" ]; then
_my_unarchiver="unzip"
_my_unarchive_opts="-qq"
_my_unarchive_out="-d"
archive_ext="zip"
else
# TODO ping bug report url
echo "Developer error: '$my_unarchiver' isn't a supported. The developer made a typo."
return 20
fi
else
echo "Failed to find '$my_unarchiver' which is needed to unpack downloaded files."
return 21
fi
set -e
}
unarchiver()
{
$_my_unarchiver $_my_unarchive_opts "$1" $_my_unarchive_out "$2"
}
detect_unarchiver
export -f unarchiver
if [ "$(uname -m | grep -i 'ARM')" ]; then
if [ "$(uname -m | grep -i 'v5')" ]; then
my_arch="armv5"
elif [ "$(uname -m | grep -i 'v6')" ]; then
my_arch="armv6"
elif [ "$(uname -m | grep -i 'v7')" ]; then
my_arch="armv7"
elif [ "$(uname -m | grep -i 'v8')" ]; then
my_arch="armv8"
elif [ "$(uname -m | grep -i '64')" ]; then
my_arch="armv8"
fi
elif [ "$(uname -m | grep -i '86')" ]; then
if [ "$(uname -m | grep -i '64')" ]; then
my_arch="amd64"
my_arch_friendly="64-bit"
else
my_arch="386"
my_arch_friendly="32-bit"
fi
elif [ "$(uname -m | grep -i '64')" ]; then
my_arch="amd64"
my_arch_friendly="64-bit"
else
http_bash https://git.coolaj86.com/coolaj86/telebit.js/raw/branch/$TELEBIT_VERSION/usr/share/install_helper.sh "$@"
>&2 echo "Your CPU doesn't appear to be 386, amd64 (x64), armv6, armv7, or armv8 (arm64)."
>&2 echo "Help us support your platform by filing an issue:"
>&2 echo " https://git.rootprojects.org/root/telebit.js/issues"
fi
export TELEBIT_ARCH="$my_arch"
export TELEBIT_OS="$my_os"
TELEBIT_VERSION=${TELEBIT_VERSION:-stable}
export TELEBIT_RELEASE=${TELEBIT_RELEASE:-$TELEBIT_VERSION}
export TELEBIT_ARCHIVER="$my_unarchiver"
echo " Operating System: $my_os_friendly"
echo " Processor Family: ${my_arch_friendly:-$my_arch}"
echo " Download Type: $archive_ext"
echo " Release Channel: $TELEBIT_VERSION"
echo ""
sleep 0.3
#echo "Downloading the Telebit installer for your system..."
#sleep 0.5
#echo ""
#if [ -e "usr/share/install_helper.sh" ]; then
# bash usr/share/install_helper.sh "$@"
#else
# http_bash https://git.coolaj86.com/coolaj86/telebit.js/raw/branch/$TELEBIT_VERSION/usr/share/install_helper.sh "$@"
#fi
mkdir -p $HOME/Downloads
my_tmp="$(mktemp -d -t telebit.XXXX)"
http_get "https://rootprojects.org/telebit/dist/index.tab" "$my_tmp/index.tab"
meta=$(grep $TELEBIT_RELEASE $my_tmp/index.tab | grep $TELEBIT_OS | grep $TELEBIT_ARCH | head -n 1)
latest=$(echo "$meta" | cut -f 1)
major=$(grep $TELEBIT_RELEASE $my_tmp/index.tab | grep $TELEBIT_OS | grep $TELEBIT_ARCH | head -n 1 | cut -f 2)
size=$(grep $TELEBIT_RELEASE $my_tmp/index.tab | grep $TELEBIT_OS | grep $TELEBIT_ARCH | head -n 1 | cut -f 3)
t_sha256=$(grep $TELEBIT_RELEASE $my_tmp/index.tab | grep $TELEBIT_OS | grep $TELEBIT_ARCH | head -n 1 | cut -f 4)
t_channel=$(grep $TELEBIT_RELEASE $my_tmp/index.tab | grep $TELEBIT_OS | grep $TELEBIT_ARCH | head -n 1 | cut -f 5)
t_os=$(grep $TELEBIT_RELEASE $my_tmp/index.tab | grep $TELEBIT_OS | grep $TELEBIT_ARCH | head -n 1 | cut -f 6)
t_arch=$(grep $TELEBIT_RELEASE $my_tmp/index.tab | grep $TELEBIT_OS | grep $TELEBIT_ARCH | head -n 1 | cut -f 7)
t_url=$(grep $TELEBIT_RELEASE $my_tmp/index.tab | grep $TELEBIT_OS | grep $TELEBIT_ARCH | head -n 1 | cut -f 8)
if [ -z "$t_url" ]; then
# TODO ping bug report url
echo "No matching version for '$TELEBIT_RELEASE' for '$TELEBIT_OS' on '$TELEBIT_ARCH'"
exit 2
fi
my_dir="telebit-$latest-$TELEBIT_OS-$TELEBIT_ARCH"
my_file="$my_dir.$archive_ext"
if [ -f "$HOME/Downloads/$my_file" ]; then
my_size=$(($(wc -c < "$HOME/Downloads/$my_file")))
if [ "$my_size" -eq "$size" ]; then
echo "~/Downloads/$my_file exists, skipping download"
sleep 0.5
else
echo "Removing incomplete download '~/Downloads/$my_file'"
# change into $HOME because we don't ever want to perform
# a destructive action on a variable we didn't set
pushd "$HOME" > /dev/null
rm -f "Downloads/$my_file"
popd > /dev/null
fi
fi
if [ ! -f "$HOME/Downloads/$my_file" ]; then
#echo "Downloading from https://rootprojects.org/telebit/dist/$major/$my_file ..."
echo "Downloading from $t_url ..."
sleep 0.3
#http_get "https://rootprojects.org/telebit/dist/$major/$my_file" "$HOME/Downloads/$my_file"
http_get "$t_url" "$HOME/Downloads/$my_file"
echo "Saved to '$HOME/Downloads/$my_file' ..."
echo ""
sleep 0.3
fi
echo "Unpacking and installing Telebit ..."
echo ""
unarchiver "$HOME/Downloads/$my_file" "$my_tmp"
# because unzip can't strip a prfeix
pushd "$my_tmp" > /dev/null
if [ -d ./telebit-* ]; then
mv ./telebit-*/* "./"
rm -rf ./telebit-*
fi
popd > /dev/null
echo "Extracted '$my_file' to '$my_tmp'"
# On linux npm is a javascript file, but on Windows (Git Bash) it's both sh and cmd,
# so we need to make sure *this* node is first in the path for this script
OLD_PATH="$PATH"
export PATH="$my_tmp/bin/:$OLD_PATH"
# make sure that telebit is not in use
pushd "$my_tmp" > /dev/null
./bin/npm --scripts-prepend-node-path=true run preinstall
popd > /dev/null
# move only once there are not likely to be any open files
# (especially important on windows)
pushd "$HOME" > /dev/null
if [ -e ".local/opt/telebit" ]; then
mv ".local/opt/telebit" ".local/opt/telebit-old-$(date "+%s")"
fi
mkdir -p .local/opt
mv "$my_tmp" ".local/opt/telebit"
popd > /dev/null
# On linux npm is a javascript file, but on Windows (Git Bash) it's both sh and cmd,
# so we need to make sure *this* node is first in the path for this script
export PATH="$HOME/.local/opt/telebit/bin/:$OLD_PATH"
# make sure that telebit is not in use
pushd "$HOME/.local/opt/telebit" > /dev/null
if [[ "$OSTYPE" == "cygwin" ]] || [[ "$OSTYPE" == "msys" ]]; then
./node_modules/.bin/pathman add '%USERPROFILE%\.local\opt\telebit\bin-public' > /dev/null &
sleep 0.1 # workaround for pathman not exiting as it should on Windows
else
./node_modules/.bin/pathman add "$HOME/.local/opt/telebit/bin-public" > /dev/null
fi
./bin/npm --scripts-prepend-node-path=true run postinstall
popd > /dev/null
echo ""
echo ""
echo ""
echo "Open a new terminal and run the following:"
echo ""
printf "\ttelebit init\n"
echo ""

591
usr/share/install_helper.sh

@ -1,574 +1,41 @@
#!/bin/bash
#<pre><code>
# What does this do.. and why?
# (and why is it so complicated?)
#
# What this does
#
# 1. Sets some vars and asks some questions
# 2. Installs everything into a single place
# (inculding deps like node.js, with the correct version)
# 3. Depending on OS, creates a user for the service
# 4. Depending on OS, register with system launcher
#
# Why
#
# So that you can get a fully configured, running product,
# with zero manual configuration in a matter of seconds -
# and have an uninstall that's just as easy.
#
# Why so complicated?
#
# To support nuance differences between various versions of
# Linux, macOS, and Android, including whether it's being
# installed with user privileges, as root, wit a system user
# system daemon launcher, etc. Also, this is designed to be
# reusable with many apps and services, so it's very variabled...
# This downloads the telebit zip (Windows) or tarball (Mac, Linux),
# unpacks it, and then completes the installation
set -e
set -u
### http_bash exported by get.sh
TELEBIT_DEBUG=${TELEBIT_DEBUG:-}
# NOTE: On OS X logname works from a pipe, but on Linux it does not
my_logname=$(who am i </dev/tty | awk '{print $1}')
#my_logname=${my_logname:-$(logname)}
#my_logname=${my_logname:-$SUDO_USER}
if [ -n "$my_logname" ] && [ "$my_logname" != "$(id -u -n)" ]; then
echo "WARNING:"
echo " You are logged in as '$(logname)' but acting as '$(id -u -n)'."
echo " If the installation is not successful please log in as '$(id -u -n)' directly."
sleep 3
fi
if [ -n "${TELEBIT_DEBUG:-}" ]; then
echo 'TELEBIT_DEBUG='${TELEBIT_DEBUG}
fi
if [ -n "${TELEBIT_PATH:-}" ]; then
echo 'TELEBIT_PATH='${TELEBIT_PATH}
fi
if [ -n "${TELEBIT_USERSPACE:-}" ]; then
echo 'TELEBIT_USERSPACE='${TELEBIT_USERSPACE}
fi
if [ -n "${TELEBIT_USER:-}" ]; then
echo 'TELEBIT_USER='${TELEBIT_USER}
fi
if [ -n "${TELEBIT_GROUP:-}" ]; then
echo 'TELEBIT_GROUP='${TELEBIT_GROUP}
fi
TELEBIT_VERSION=${TELEBIT_VERSION:-master}
TELEBIT_USERSPACE=${TELEBIT_USERSPACE:-no}
my_email=${1:-}
my_relay=${2:-}
my_servernames=${3:-}
my_secret=${4:-}
cur_user="$(id -u -n)"
TELEBIT_USER="${TELEBIT_USER:-$cur_user}"
cur_group="$(id -g -n)"
TELEBIT_GROUP="${TELEBIT_GROUP:-$cur_group}"
my_app_pkg_name="cloud.telebit.remote"
my_app="telebit"
my_daemon="telebitd"
my_bin="telebit.js"
my_name="Telebit Remote"
my_repo="telebit.js"
my_root=${my_root:-} # todo better install script
soft_sudo_cmd="sudo"
soft_sudo_cmde="sudo "
exec 3<>/dev/tty
read_cmd="read -u 3"
# TODO detect if rsync is available and use rsync -a (more portable)
rsync_cmd="cp -pPR"
set +e
my_edit=$(basename "${EDITOR:-}")
if [ -z "$my_edit" ]; then
my_edit=$(basename "$(type -p edit)")
fi
if [ -z "$my_edit" ]; then
my_edit=$(basename "$(type -p nano)")
fi
if [ -z "$my_edit" ]; then
my_edit=$(basename "$(type -p vim)")
fi
if [ -z "$my_edit" ]; then
my_edit=$(basename "$(type -p vi)")
fi
if [ -z "$my_edit" ]; then
my_edit="nano"
fi
set -e
if [ "root" == $(whoami) ] || [ 0 == $(id -u) ]; then
soft_sudo_cmd=" "
soft_sudo_cmde=""
fi
echo ""
TELEBIT_REAL_PATH=${TELEBIT_PATH:-}
if [ $(id -u) -ne 0 ] && [ "$TELEBIT_USER" == "$cur_user" ]; then
TELEBIT_USERSPACE="yes"
if [ -z "${TELEBIT_REAL_PATH:-}" ]; then
TELEBIT_REAL_PATH=$HOME/Applications/$my_app
fi
else
TELEBIT_USERSPACE="no"
if [ -z "${TELEBIT_REAL_PATH:-}" ]; then
TELEBIT_REAL_PATH=/opt/$my_app
fi
fi
TELEBIT_PATH="$TELEBIT_REAL_PATH"
TELEBIT_TMP="$TELEBIT_REAL_PATH"
# this works slightly differently between bsd (macOS) and gnu mktemp
# bsd requires the Xes for templates while GNU uses them literally
my_tmp="$(mktemp -d -t telebit.XXXXXXXX)"
#TELEBIT_TMP="$my_tmp/telebit"
echo "Installing $my_name to '$TELEBIT_REAL_PATH'"
# v10.2+ has much needed networking fixes, but breaks ursa.
# v9.x has severe networking bugs.
# v8.x has working ursa, but requires tls workarounds"
# v10.13 seems to work for me locally (new greenlock)
NODEJS_VER="${NODEJS_VER:-v10.13}"
export NODEJS_VER
export NODE_PATH="$TELEBIT_TMP/lib/node_modules"
export NPM_CONFIG_PREFIX="$TELEBIT_TMP"
# this comes last for security
export PATH="$PATH:$TELEBIT_REAL_PATH/bin"
sleep 0.25
real_sudo_cmd=$soft_sudo_cmd
real_sudo_cmde=$soft_sudo_cmde
set +e
mkdir -p $my_tmp "$TELEBIT_REAL_PATH" "$TELEBIT_REAL_PATH/etc" "$TELEBIT_REAL_PATH/var/log" 2>/dev/null && \
chown -R $(id -u -n):$(id -g -n) $my_tmp "$TELEBIT_REAL_PATH" 2>/dev/null
if [ $? -eq 0 ]; then
soft_sudo_cmd=" "
soft_sudo_cmde=""
else
$soft_sudo_cmd mkdir -p $my_tmp "$TELEBIT_REAL_PATH" "$TELEBIT_REAL_PATH/etc" "$TELEBIT_REAL_PATH/var/log"
$soft_sudo_cmd chown -R $(id -u -n):$(id -g -n) $my_tmp "$TELEBIT_REAL_PATH"
fi
set -e
if [ -n "${TELEBIT_DEBUG}" ]; then
echo " - installing node.js runtime to '$TELEBIT_REAL_PATH'..."
http_bash https://git.coolaj86.com/coolaj86/node-installer.sh/raw/branch/master/install.sh --no-dev-deps
else
echo -n "."
#bash -c 'while true; do echo -n "."; sleep 2; done' 2>/dev/null &
#_my_pid=$!
http_bash https://git.coolaj86.com/coolaj86/node-installer.sh/raw/branch/master/install.sh --no-dev-deps >/dev/null 2>/dev/null
#kill $_my_pid >/dev/null 2>/dev/null
fi
#
# TODO create "upgrade" script and run that instead
#
my_node="$TELEBIT_REAL_PATH/bin/node"
tmp_node="$TELEBIT_TMP/bin/node"
my_npm="$my_node $TELEBIT_TMP/bin/npm"
tmp_npm="$tmp_node $TELEBIT_TMP/bin/npm"
#https://git.coolaj86.com/coolaj86/telebit.js.git
#https://git.coolaj86.com/coolaj86/telebit.js/archive/:tree:.tar.gz
#https://git.coolaj86.com/coolaj86/telebit.js/archive/:tree:.zip
set +e
my_unzip=$(type -p unzip)
my_tar=$(type -p tar)
# TODO extract to temporary directory, configure, copy etc, replace
if [ -n "$my_unzip" ]; then
rm -f $my_tmp/$my_app-$TELEBIT_VERSION.zip
if [ -n "${TELEBIT_DEBUG}" ]; then
echo " - installing telebit zip to '$TELEBIT_REAL_PATH'"
fi
echo -n "."
#bash -c 'while true; do echo -n "."; sleep 2; done' 2>/dev/null &
#_my_pid=$!
http_get https://git.coolaj86.com/coolaj86/$my_repo/archive/$TELEBIT_VERSION.zip $my_tmp/$my_app-$TELEBIT_VERSION.zip
#kill $_my_pid >/dev/null 2>/dev/null
# -o means overwrite, and there is no option to strip
$my_unzip -o $my_tmp/$my_app-$TELEBIT_VERSION.zip -d $my_tmp/ >/dev/null
$rsync_cmd $my_tmp/$my_repo/* $TELEBIT_TMP/ > /dev/null
rm -rf $my_tmp/$my_repo
elif [ -n "$my_tar" ]; then
rm -f $my_tmp/$my_app-$TELEBIT_VERSION.tar.gz
if [ -n "${TELEBIT_DEBUG}" ]; then
echo " - installing telebit tar.gz to '$TELEBIT_REAL_PATH'"
fi
echo -n "."
#bash -c 'while true; do echo -n "."; sleep 2; done' 2>/dev/null &
#_my_pid=$!
http_get https://git.coolaj86.com/coolaj86/$my_repo/archive/$TELEBIT_VERSION.tar.gz $my_tmp/$my_app-$TELEBIT_VERSION.tar.gz
#kill $_my_pid >/dev/null 2>/dev/null
$my_tar -xzf $my_tmp/$my_app-$TELEBIT_VERSION.tar.gz --strip 1 -C $TELEBIT_TMP/ >/dev/null
else
echo "Neither tar nor unzip found. Abort."
exit 13
fi
set -e
#
# TODO create slim packages that contain all the deps on each os and cpu
#
pushd $TELEBIT_TMP >/dev/null
if [ -n "${TELEBIT_DEBUG}" ]; then
echo " - installing telebit npm dependencies to '$TELEBIT_REAL_PATH'..."
### http_get, http_bash, archiver, and archive_ext are exported by get.sh
mkdir -p $HOME/Downloads
my_tmp="$(mktemp -d -t telebit.XXXX)"
http_get "https://rootprojects.org/telebit/dist/index.tab" "$my_tmp/index.tab"
latest=$(grep $TELEBIT_RELEASE $my_tmp/index.tab | grep $TELEBIT_OS | grep $TELEBIT_ARCH | head -n 1 | cut -f 1)
major=$(grep $TELEBIT_RELEASE $my_tmp/index.tab | grep $TELEBIT_OS | grep $TELEBIT_ARCH | head -n 1 | cut -f 2)
size=$(grep $TELEBIT_RELEASE $my_tmp/index.tab | grep $TELEBIT_OS | grep $TELEBIT_ARCH | head -n 1 | cut -f 3)
#latest=$(grep $TELEBIT_RELEASE $my_tmp/index.tab | grep $TELEBIT_OS | grep $TELEBIT_ARCH | head -n 1 | cut -f 1)
my_dir="telebit-$latest-$TELEBIT_OS-$TELEBIT_ARCH"
my_file="$my_dir.$archive_ext"
if [ -f "$HOME/Downloads/$my_file" ]; then
my_size=$(($(wc -c < "$HOME/Downloads/$my_file")))
if [ "$my_size" -eq "$size" ]; then
echo "File exists in ~/Downloads, skipping download"
else
echo -n "."
echo "Removing corrupt download '~/Downloads/$my_file'"
rm -f "$HOME/Downloads/$my_file"
fi
set +e
$tmp_npm install >/dev/null 2>/dev/null &
tmp_npm_pid=$!
while [ -n "$tmp_npm_pid" ]; do
sleep 2
echo -n "."
kill -s 0 $tmp_npm_pid >/dev/null 2>/dev/null || tmp_npm_pid=""
done
set -e
echo -n "."
$tmp_npm install >/dev/null 2>/dev/null
# ursa is now an entirely optional dependency for key generation
# but very much needed on ARM devices
$tmp_npm install ursa >/dev/null 2>/dev/null || true
popd >/dev/null
if [ -n "${TELEBIT_DEBUG}" ]; then
echo " - configuring telebit..."
echo ""
fi
###############################################
#
# TODO convert to node script
#
# Now that node is installed and the telebit
# packeage is downloaded, everything can be
# run from node, except things requiring sudo
#
###############################################
# telebit remote
echo '#!/bin/bash' > "$TELEBIT_TMP/bin/$my_app"
echo "$my_node $TELEBIT_REAL_PATH/bin/$my_bin "'"$@"' >> "$TELEBIT_TMP/bin/$my_app"
chmod a+x "$TELEBIT_TMP/bin/$my_app"
# telebit daemon
echo '#!/bin/bash' > "$TELEBIT_TMP/bin/$my_daemon"
echo "$my_node $TELEBIT_REAL_PATH/bin/$my_daemon.js daemon "'"$@"' >> "$TELEBIT_TMP/bin/$my_daemon"
chmod a+x "$TELEBIT_TMP/bin/$my_daemon"
# Create uninstall script based on the install script variables
cat << EOF > $TELEBIT_TMP/bin/${my_app}_uninstall
#!/bin/bash
set -x
if [ "$(type -p launchctl)" ]; then
sudo launchctl unload -w /Library/LaunchDaemons/${my_app_pkg_name}.plist
sudo rm -f /Library/LaunchDaemons/${my_app_pkg_name}.plist
launchctl unload -w $HOME/Library/LaunchAgents/${my_app_pkg_name}.plist
rm -f $HOME/Library/LaunchAgents/${my_app_pkg_name}.plist
fi
if [ "$(type -p systemctl)" ]; then
systemctl --user disable $my_app >/dev/null
systemctl --user stop $my_app
rm -f $HOME/.config/systemd/user/$my_app.service
sudo systemctl disable $my_app >/dev/null
sudo systemctl stop $my_app
sudo rm -f /etc/systemd/system/$my_app.service
fi
sudo rm -rf $TELEBIT_REAL_PATH /usr/local/bin/$my_app
sudo rm -rf $TELEBIT_REAL_PATH /usr/local/bin/$my_daemon
rm -rf $HOME/.config/$my_app $HOME/.local/share/$my_app
EOF
chmod a+x $TELEBIT_TMP/bin/${my_app}_uninstall
#set +e
#if type -p setcap >/dev/null 2>&1; then
# #echo "Setting permissions to allow $my_app to run on port 80 and port 443 without sudo or root"
# echo " > ${real_sudo_cmde}setcap cap_net_bind_service=+ep $TELEBIT_REAL_PATH/bin/node"
# $real_sudo_cmd setcap cap_net_bind_service=+ep $TELEBIT_REAL_PATH/bin/node
#fi
#set -e
my_skip=""
set +e
# TODO for macOS https://apple.stackexchange.com/questions/286749/how-to-add-a-user-from-the-command-line-in-macos
# TODO do stuff for groups too
# TODO add ending $
if type -p dscl >/dev/null 2>/dev/null; then
if [ -n "$(dscl . list /users | grep ^$TELEBIT_USER)" ] && [ -n "$(dscl . list /groups | grep ^$TELEBIT_GROUP)" ]; then
my_skip="yes"
fi
elif [ -n "$(cat $my_root/etc/passwd | grep $TELEBIT_USER)" ] && [ -n "$(cat $my_root/etc/group | grep $TELEBIT_GROUP)" ]; then
my_skip="yes"
fi
if [ -z "$my_skip" ]; then
if type -p adduser >/dev/null 2>/dev/null; then
$real_sudo_cmd adduser --home $TELEBIT_REAL_PATH --gecos '' --disabled-password $TELEBIT_USER >/dev/null 2>&1
#TELEBIT_USER=$my_app_name
TELEBIT_GROUP=$TELEBIT_USER
elif [ -n "$(cat /etc/passwd | grep www-data:)" ]; then
# Linux (Ubuntu)
TELEBIT_USER=www-data
TELEBIT_GROUP=www-data
elif [ -n "$(cat /etc/passwd | grep _www:)" ]; then
# Mac
TELEBIT_USER=_www
TELEBIT_GROUP=_www
else
# Unsure
TELEBIT_USER=$(id -u -n) # $(whoami)
TELEBIT_GROUP=$(id -g -n)
fi
fi
set -e
export TELEBIT_USER
export TELEBIT_GROUP
export TELEBIT_PATH
export TELEBIT_CONFIG=$HOME/.config/$my_app/$my_app.yml
# TODO check both expected sock paths in client by default
if [ "yes" == "$TELEBIT_USERSPACE" ]; then
TELEBIT_TMP_CONFIGD=$HOME/.config/$my_app/$my_daemon.yml
TELEBITD_CONFIG=$HOME/.config/$my_app/$my_daemon.yml
TELEBIT_LOG_DIR=${TELEBIT_LOG_DIR:-$HOME/.local/share/$my_app/var/log/}
TELEBIT_SOCK_DIR=${TELEBIT_SOCK_DIR:-$HOME/.local/share/$my_app/var/run/}
TELEBIT_SOCK=${TELEBIT_SOCK:-$HOME/.local/share/$my_app/var/run/$my_app.sock}
else
TELEBIT_TMP_CONFIGD=$TELEBIT_TMP/etc/$my_daemon.yml
TELEBITD_CONFIG=$TELEBIT_REAL_PATH/etc/$my_daemon.yml
TELEBIT_LOG_DIR=${TELEBIT_LOG_DIR:-$TELEBIT_REAL_PATH/var/log/}
TELEBIT_SOCK_DIR=${TELEBIT_SOCK_DIR:-$TELEBIT_REAL_PATH/var/run/}
TELEBIT_SOCK=${TELEBIT_SOCK:-$TELEBIT_REAL_PATH/var/run/$my_app.sock}
fi
export TELEBITD_CONFIG
export TELEBIT_SOCK
export TELEBIT_NODE=$TELEBIT_REAL_PATH/bin/node
export TELEBIT_NPM=$TELEBIT_REAL_PATH/bin/npm
export TELEBIT_BIN=$TELEBIT_REAL_PATH/bin/telebit
export TELEBITD_BIN=$TELEBIT_REAL_PATH/bin/telebitd
export TELEBIT_JS=$TELEBIT_REAL_PATH/bin/telebit.js
export TELEBITD_JS=$TELEBIT_REAL_PATH/bin/telebitd.js
export TELEBIT_LOG_DIR
export TELEBIT_SOCK_DIR
export NODE_PATH="$TELEBIT_REAL_PATH/lib/node_modules"
export NPM_CONFIG_PREFIX="$TELEBIT_REAL_PATH"
$my_node $TELEBIT_TMP/usr/share/template-launcher.js
# TODO don't create this in TMP_PATH if it exists in TELEBIT_REAL_PATH
mkdir -p "$(dirname $TELEBIT_TMP_CONFIGD)"
if [ ! -e "$TELEBITD_CONFIG" ]; then
echo "sock: $TELEBIT_SOCK" >> "$TELEBIT_TMP_CONFIGD"
echo "root: $TELEBIT_REAL_PATH" >> "$TELEBIT_TMP_CONFIGD"
cat $TELEBIT_REAL_PATH/usr/share/$my_daemon.tpl.yml >> "$TELEBIT_TMP_CONFIGD"
fi
mkdir -p "$(dirname $TELEBIT_CONFIG)"
if [ ! -e "$TELEBIT_CONFIG" ]; then
echo "sock: $TELEBIT_SOCK" >> "$TELEBIT_CONFIG"
fi
# TODO
# Backup final directory, if it exists
# Move everything over to final directory
# Restore config files, if they exist
# rewrite system service file with real variables
# This should only affect non-USERSPACE installs
#echo "${soft_sudo_cmde}chown -R $TELEBIT_USER '$TELEBIT_REAL_PATH'
$soft_sudo_cmd mkdir -p $TELEBIT_LOG_DIR
$soft_sudo_cmd mkdir -p $TELEBIT_SOCK_DIR
$soft_sudo_cmd chown -R $TELEBIT_USER "$TELEBIT_REAL_PATH"
# $HOME/.config/systemd/user/
# %h/.config/telebit/telebit.yml
if [ -n "${TELEBIT_DEBUG}" ]; then
echo " - adding $my_app as a system service"
fi
# TODO detect with type -p
my_system_launcher=""
my_app_launchd_service=""
if [ -d "/Library/LaunchDaemons" ]; then
my_system_launcher="launchd"
my_sudo_cmde="$real_sudo_cmde"
my_sudo_cmd="$real_sudo_cmd"
if [ "yes" == "$TELEBIT_USERSPACE" ]; then
my_app_launchd_service_skel="etc/skel/Library/LaunchAgents/${my_app_pkg_name}.plist"
my_app_launchd_service="$HOME/Library/LaunchAgents/${my_app_pkg_name}.plist"
if [ -n "${TELEBIT_DEBUG}" ]; then
echo " > $rsync_cmd $TELEBIT_REAL_PATH/usr/share/dist/$my_app_launchd_service $my_app_launchd_service"
fi
mkdir -p $HOME/Library/LaunchAgents
$rsync_cmd "$TELEBIT_REAL_PATH/usr/share/dist/$my_app_launchd_service_skel" "$my_app_launchd_service"
if [ -n "${TELEBIT_DEBUG}" ]; then
echo " > chown $(id -u -n):$(id -g -n) $my_app_launchd_service"
fi
chown $(id -u -n):$(id -g -n) "$my_app_launchd_service"
my_sudo_cmd=""
my_sudo_cmde=""
if [ -n "${TELEBIT_DEBUG}" ]; then
echo " > launchctl unload -w $my_app_launchd_service >/dev/null 2>/dev/null"
fi
launchctl unload -w "$my_app_launchd_service" >/dev/null 2>/dev/null
else
my_app_launchd_service_skel="usr/share/dist/Library/LaunchDaemons/${my_app_pkg_name}.plist"
my_app_launchd_service="$my_root/Library/LaunchDaemons/${my_app_pkg_name}.plist"
echo " > ${real_sudo_cmde}$rsync_cmd $TELEBIT_REAL_PATH/usr/share/dist/$my_app_launchd_service $my_app_launchd_service"
$real_sudo_cmd $rsync_cmd "$TELEBIT_REAL_PATH/usr/share/dist/$my_app_launchd_service_skel" "$my_app_launchd_service"
echo " > ${real_sudo_cmde}chown root:wheel $my_app_launchd_service"
$real_sudo_cmd chown root:wheel "$my_app_launchd_service"
echo " > ${real_sudo_cmde}launchctl unload -w $my_app_launchd_service >/dev/null 2>/dev/null"
$real_sudo_cmd launchctl unload -w "$my_app_launchd_service" >/dev/null 2>/dev/null
fi
elif [ -d "$my_root/etc/systemd/system" ]; then
my_system_launcher="systemd"
if [ "yes" == "$TELEBIT_USERSPACE" ]; then
if [ -n "${TELEBIT_DEBUG}" ]; then
echo " > $rsync_cmd $TELEBIT_REAL_PATH/usr/share/dist/etc/skel/.config/systemd/user/$my_app.service $HOME/.config/systemd/user/$my_app.service"
fi
mkdir -p $HOME/.config/systemd/user
$rsync_cmd "$TELEBIT_REAL_PATH/usr/share/dist/etc/skel/.config/systemd/user/$my_app.service" "$HOME/.config/systemd/user/$my_app.service"
else
echo " > ${real_sudo_cmde}$rsync_cmd $TELEBIT_REAL_PATH/usr/share/dist/etc/systemd/system/$my_app.service /etc/systemd/system/$my_app.service"
$real_sudo_cmd $rsync_cmd "$TELEBIT_REAL_PATH/usr/share/dist/etc/systemd/system/$my_app.service" "/etc/systemd/system/$my_app.service"
fi
fi
sleep 1
###############################
# Actually Launch the Service #
###############################
if [ -n "${TELEBIT_DEBUG}" ]; then
if [ ! -f "$HOME/Downloads/$my_file" ]; then
echo "Downloading from https://rootprojects.org/telebit/dist/$major/$my_file ..."
sleep 0.3
http_get "https://rootprojects.org/telebit/dist/$major/$my_file" "$HOME/Downloads/$my_file"
echo "Saved to '$HOME/Downloads/$my_file' ..."
echo ""
sleep 0.3
fi
if [ "launchd" == "$my_system_launcher" ]; then
if [ "yes" == "$TELEBIT_USERSPACE" ]; then
if [ -n "${TELEBIT_DEBUG}" ]; then
echo " > launchctl load -w $my_app_launchd_service"
else
echo -n "."
fi
launchctl load -w "$my_app_launchd_service"
else
echo " > ${real_sudo_cmde}launchctl load -w $my_app_launchd_service"
$real_sudo_cmd launchctl load -w "$my_app_launchd_service"
fi
sleep 2; # give it time to start
elif [ "systemd" == "$my_system_launcher" ]; then
if [ "yes" == "$TELEBIT_USERSPACE" ]; then
# https://wiki.archlinux.org/index.php/Systemd/User
# sudo loginctl enable-linger username
if [ -n "${TELEBIT_DEBUG}" ]; then
echo " > systemctl --user enable $my_app"
else
echo -n "."
fi
set +e
if systemctl --user daemon-reload; then
# enable also puts success output to stderr... why?
systemctl --user enable $my_app >/dev/null 2>/dev/null
#echo " > systemctl --user enable systemd-tmpfiles-setup.service systemd-tmpfiles-clean.timer"
#systemctl --user enable systemd-tmpfiles-setup.service systemd-tmpfiles-clean.timer
if [ -n "${TELEBIT_DEBUG}" ]; then
echo " > systemctl --user start $my_app"
fi
systemctl --user stop $my_app >/dev/null 2>/dev/null
systemctl --user start $my_app >/dev/null
sleep 2; # give it time to start
_is_running=$(systemctl --user status --no-pager $my_app 2>/dev/null | grep "active.*running")
if [ -z "$_is_running" ]; then
echo "Something went wrong:"
systemctl --user status --no-pager $my_app
fi
else
echo "libpam-systemd is missing, which is required on Linux to register Telebit with the user launcher."
echo "sudo apt-get install -y libpam-systemd"
sudo apt-get install -y libpam-systemd
fi
set -e
echo -n "."
else
$real_sudo_cmd systemctl daemon-reload
echo " > ${real_sudo_cmde}systemctl enable $my_app"
$real_sudo_cmd systemctl enable $my_app >/dev/null
echo " > ${real_sudo_cmde}systemctl start $my_app"
$real_sudo_cmd systemctl daemon-reload
$real_sudo_cmd systemctl restart $my_app
sleep 2; # give it time to start
$real_sudo_cmd systemctl status --no-pager $my_app
fi
else
echo "Run the service manually (we couldn't detect your system service to do that automatically):"
echo ""
echo " $TELEBITD_BIN --config $TELEBITD_CONFIG"
echo " ~/$my_app --config $TELEBIT_CONFIG"
fi
# NOTE: ln -sf *should* replace an existing link... but sometimes it doesn't, hence rm -f
if [ "yes" == "$TELEBIT_USERSPACE" ]; then
if [ -n "${TELEBIT_DEBUG}" ]; then
echo " > ${real_sudo_cmde}ln -sf $TELEBIT_REAL_PATH/bin/$my_app /usr/local/bin/$my_app"
fi
rm -f /usr/local/bin/$my_app 2>/dev/null || true
ln -sf $TELEBIT_REAL_PATH/bin/$my_app /usr/local/bin/$my_app 2>/dev/null || true
else
echo " > ${real_sudo_cmde}ln -sf $TELEBIT_REAL_PATH/bin/$my_app /usr/local/bin/$my_app"
rm -f /usr/local/bin/$my_app 2>/dev/null || \
$real_sudo_cmd rm -f /usr/local/bin/$my_app
ln -sf $TELEBIT_REAL_PATH/bin/$my_app /usr/local/bin/$my_app 2>/dev/null || \
$real_sudo_cmd ln -sf $TELEBIT_REAL_PATH/bin/$my_app /usr/local/bin/$my_app
# telebitd
echo " > ${real_sudo_cmde}ln -sf $TELEBIT_REAL_PATH/bin/$my_daemon /usr/local/bin/$my_daemon"
rm -f $TELEBIT_REAL_PATH/bin/$my_daemon || $real_sudo_cmd rm -f $TELEBIT_REAL_PATH/bin/$my_daemon
ln -sf $TELEBIT_REAL_PATH/bin/$my_daemon /usr/local/bin/$my_daemon || \
$real_sudo_cmd ln -sf $TELEBIT_REAL_PATH/bin/$my_daemon /usr/local/bin/$my_daemon
fi
rm -f $HOME/$my_app; ln -s $TELEBIT_REAL_PATH/bin/$my_app $HOME/
if [ -n "${TELEBIT_DEBUG}" ]; then
echo " > telebit init --tty"
echo ""
fi
sleep 0.25
echo ""
$TELEBIT_REAL_PATH/bin/node $TELEBIT_REAL_PATH/bin/telebit.js init --tty
echo "Unpacking and installing Telebit ..."
unarchiver $my_file $my_tmp
pushd $my_tmp/$my_dir
bash ./setup.sh

5
usr/share/telebitd.tpl.yml

@ -1,5 +0,0 @@
#agree_tos: true # agree to the Telebit, Greenlock, and Let's Encrypt TOSes
community_member: true # receive infrequent relevant updates
telemetry: true # contribute to project telemetric data
newsletter: false # contribute to project telemetric data
ssh_auto: false # forward ssh-looking packets, from any connection, to port 22

97
usr/share/template-launcher.js

@ -1,97 +0,0 @@
'use strict';
var path = require('path');
var fs = require('fs');
var os = require('os');
module.exports = function (opts, fn) {
// TODO make async version
try {
module.exports.sync(opts);
} catch(e) {
if (fn) { fn(e); }
}
if (fn) { fn(null); }
};
module.exports.sync = function (opts) {
var f = opts.file;
var vars = opts.vars;
var text = fs.readFileSync(f.tpl, 'utf8')
.replace(/{TELEBIT_PATH}/g, vars.telebitPath || '{TELEBIT_PATH}')
.replace(/{TELEBIT_NODE}/g, vars.telebitNode || '{TELEBIT_NODE}')
.replace(/{NODE_PATH}/g, vars.nodePath || '{NODE_PATH}')
.replace(/{NPM_CONFIG_PREFIX}/g, vars.npmConfigPrefix || '{NPM_CONFIG_PREFIX}')
.replace(/{TELEBIT_NPM}/g, vars.telebitNpm || '{TELEBIT_NPM}')
.replace(/{TELEBIT_BIN}/g, vars.telebitBin || '{TELEBIT_BIN}')
.replace(/{TELEBITD_BIN}/g, vars.telebitdBin || '{TELEBITD_BIN}')
.replace(/{TELEBIT_JS}/g, vars.telebitJs || '{TELEBIT_JS}')
.replace(/{TELEBITD_JS}/g, vars.telebitdJs || '{TELEBITD_JS}')
.replace(/{TELEBIT_USER}/g, vars.telebitUser || '{TELEBIT_USER}')
.replace(/{TELEBIT_GROUP}/g, vars.telebitGroup || '{TELEBIT_GROUP}')
.replace(/{TELEBIT_RW_DIRS}/g, vars.telebitRwDirs || '{TELEBIT_RW_DIRS}')
.replace(/{TELEBIT_CONFIG}/g, vars.telebitConfig || '{TELEBIT_CONFIG}')
.replace(/{TELEBITD_CONFIG}/g, vars.telebitdConfig || '{TELEBITD_CONFIG}')
.replace(/{TELEBIT_LOG_DIR}/g, vars.TELEBIT_LOG_DIR || '{TELEBIT_LOG_DIR}')
.replace(/{TELEBIT_SOCK_DIR}/g, vars.TELEBIT_LOG_DIR || '{TELEBIT_SOCK_DIR}')
;
fs.writeFileSync(f.launcher, text, 'utf8');
if (f.executable && !/^win/i.test(os.platform())) {
// TODO not sure if chmod works on windows
fs.chmodSync(f.launcher, parseInt('755', 8));
}
};
function run() {
var files = [
{ tpl: (process.env.TELEBIT_SERVICE_TPL || path.join(__dirname, 'dist/etc/systemd/system/telebit.service.tpl'))
, launcher: (process.env.TELEBIT_SERVICE || path.join(__dirname, 'dist/etc/systemd/system/telebit.service'))
}
, { tpl: (process.env.TELEBIT_USER_SERVICE_TPL || path.join(__dirname, 'dist/etc/skel/.config/systemd/user/telebit.service.tpl'))
, launcher: (process.env.TELEBIT_USER_SERVICE || path.join(__dirname, 'dist/etc/skel/.config/systemd/user/telebit.service'))
}
, { tpl: (process.env.TELEBIT_PLIST_TPL || path.join(__dirname, 'dist/Library/LaunchDaemons/cloud.telebit.remote.plist.tpl'))
, launcher: (process.env.TELEBIT_PLIST || path.join(__dirname, 'dist/Library/LaunchDaemons/cloud.telebit.remote.plist'))
}
, { tpl: (process.env.TELEBIT_USER_PLIST_TPL || path.join(__dirname, 'dist/etc/skel/Library/LaunchAgents/cloud.telebit.remote.plist.tpl'))
, launcher: (process.env.TELEBIT_USER_PLIST || path.join(__dirname, 'dist/etc/skel/Library/LaunchAgents/cloud.telebit.remote.plist'))
}
];
files.forEach(function (f) {
var telebitRoot = path.resolve(__dirname, '../..');
var vars = {
telebitPath: process.env.TELEBIT_PATH || telebitRoot
, telebitNode: process.env.TELEBIT_NODE || process.argv[0] || path.resolve(telebitRoot, 'bin/node')
, telebitBin: process.env.TELEBIT_BIN || path.resolve(telebitRoot, 'bin/telebit')
, telebitdBin: process.env.TELEBITD_BIN || path.resolve(telebitRoot, 'bin/telebitd')
, telebitJs: process.env.TELEBIT_JS || path.resolve(telebitRoot, 'bin/telebit.js')
, telebitdJs: process.env.TELEBITD_JS || path.resolve(telebitRoot, 'bin/telebitd.js')
, telebitRwDirs: [
(process.env.TELEBIT_PATH || path.resolve(__dirname, '../..'))
, path.join(os.homedir(), '.config/telebit')
, path.join(os.homedir(), '.local/share/telebit')
]
, telebitUser: process.env.TELEBIT_USER || os.userInfo().username
, telebitGroup: process.env.TELEBIT_GROUP || ('darwin' === os.platform() ? 'staff' : os.userInfo().username)
, telebitConfig: process.env.TELEBIT_CONFIG || path.join(os.homedir(), '.config/telebit/telebit.yml')
, telebitdConfig: process.env.TELEBITD_CONFIG || path.join(os.homedir(), '.config/telebit/telebitd.yml')
, TELEBIT_LOG_DIR: process.env.TELEBIT_LOG_DIR || path.join(os.homedir(), '.local/share/telebit/var/log')
};
vars.telebitNpm = process.env.TELEBIT_NPM || path.resolve(vars.telebitNode, '../npm');
vars.nodePath = process.env.NODE_PATH || path.resolve(vars.telebitNode, '../../lib/node_modules');
vars.npmConfigPrefix = process.env.NPM_CONFIG_PREFIX || path.resolve(vars.telebitNode, '..', '..');
if (-1 === vars.telebitRwDirs.indexOf(vars.npmConfigPrefix)) {
vars.telebitRwDirs.push(vars.npmConfigPrefix);
}
vars.telebitRwDirs = vars.telebitRwDirs.join(' ');
module.exports({
file: f
, vars: vars
});
});
}
if (module === require.main) {
run();
}
Loading…
Cancel
Save