cleanup
This commit is contained in:
parent
eef6ca679f
commit
c234077fdc
18
.jshintrc
18
.jshintrc
|
@ -1,18 +0,0 @@
|
||||||
{ "node": true
|
|
||||||
, "browser": true
|
|
||||||
, "jquery": true
|
|
||||||
, "globals": { "angular": true, "Promise": true }
|
|
||||||
|
|
||||||
, "indent": 2
|
|
||||||
, "onevar": true
|
|
||||||
, "laxcomma": true
|
|
||||||
, "laxbreak": true
|
|
||||||
, "curly": true
|
|
||||||
, "nonbsp": true
|
|
||||||
|
|
||||||
, "eqeqeq": true
|
|
||||||
, "immed": true
|
|
||||||
, "undef": true
|
|
||||||
, "unused": true
|
|
||||||
, "latedef": true
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
// +build !dev
|
// +build !dev
|
||||||
//go:generate go run -mod vendor github.com/shurcooL/vfsgen/cmd/vfsgendev -source="git.rootprojects.org/root/telebit/admin".AdminFS
|
//go:generate go run -mod vendor github.com/shurcooL/vfsgen/cmd/vfsgendev -source="git.rootprojects.org/root/telebit/assets/admin".AdminFS
|
||||||
|
|
||||||
package admin
|
package admin
|
|
@ -1,4 +1,4 @@
|
||||||
// +build !dev
|
// +build !dev
|
||||||
//go:generate go run -mod vendor github.com/shurcooL/vfsgen/cmd/vfsgendev -source="git.rootprojects.org/root/telebit/files".Assets
|
//go:generate go run -mod vendor github.com/shurcooL/vfsgen/cmd/vfsgendev -source="git.rootprojects.org/root/telebit/assets/files".Assets
|
||||||
|
|
||||||
package files
|
package files
|
|
@ -1,6 +0,0 @@
|
||||||
go generate ./...
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -mod vendor -o mgmt-server-linux ./cmd/mgmt/*.go
|
|
||||||
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -mod vendor -o mgmt-server-macos ./cmd/mgmt/*.go
|
|
||||||
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -mod vendor -o mgmt-server-windows-debug.exe ./cmd/mgmt/*.go
|
|
||||||
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -mod vendor -ldflags "-H windowsgui" -o mgmt-server-windows.exe ./cmd/mgmt/*.go
|
|
|
@ -1,11 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
set -u
|
|
||||||
|
|
||||||
go generate ./...
|
|
||||||
|
|
||||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -mod vendor -o telebit-relay-linux ./cmd/telebit/*.go
|
|
||||||
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -mod vendor -o telebit-relay-macos ./cmd/telebit/*.go
|
|
||||||
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -mod vendor -o telebit-relay-windows-debug.exe ./cmd/telebit/*.go
|
|
||||||
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -mod vendor -ldflags "-H windowsgui" -o telebit-relay-windows.exe ./cmd/telebit/*.go
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.rootprojects.org/root/telebit/iplist"
|
"git.rootprojects.org/root/telebit/internal/iplist"
|
||||||
)
|
)
|
||||||
|
|
||||||
func help() {
|
func help() {
|
||||||
|
|
|
@ -11,9 +11,9 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.rootprojects.org/root/telebit"
|
"git.rootprojects.org/root/telebit/internal/dbg"
|
||||||
"git.rootprojects.org/root/telebit/dbg"
|
|
||||||
"git.rootprojects.org/root/telebit/internal/mgmt/authstore"
|
"git.rootprojects.org/root/telebit/internal/mgmt/authstore"
|
||||||
|
"git.rootprojects.org/root/telebit/internal/telebit"
|
||||||
|
|
||||||
"github.com/denisbrodbeck/machineid"
|
"github.com/denisbrodbeck/machineid"
|
||||||
_ "github.com/joho/godotenv/autoload"
|
_ "github.com/joho/godotenv/autoload"
|
||||||
|
|
|
@ -19,17 +19,15 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.rootprojects.org/root/telebit"
|
"git.rootprojects.org/root/telebit/internal/dbg"
|
||||||
"git.rootprojects.org/root/telebit/dbg"
|
|
||||||
"git.rootprojects.org/root/telebit/internal/dns01"
|
"git.rootprojects.org/root/telebit/internal/dns01"
|
||||||
"git.rootprojects.org/root/telebit/internal/http01"
|
"git.rootprojects.org/root/telebit/internal/http01"
|
||||||
|
"git.rootprojects.org/root/telebit/internal/iplist"
|
||||||
"git.rootprojects.org/root/telebit/internal/mgmt"
|
"git.rootprojects.org/root/telebit/internal/mgmt"
|
||||||
"git.rootprojects.org/root/telebit/internal/mgmt/authstore"
|
"git.rootprojects.org/root/telebit/internal/mgmt/authstore"
|
||||||
"git.rootprojects.org/root/telebit/internal/service"
|
"git.rootprojects.org/root/telebit/internal/service"
|
||||||
telebitX "git.rootprojects.org/root/telebit/internal/telebit"
|
"git.rootprojects.org/root/telebit/internal/telebit"
|
||||||
"git.rootprojects.org/root/telebit/iplist"
|
"git.rootprojects.org/root/telebit/internal/tunnel"
|
||||||
"git.rootprojects.org/root/telebit/table"
|
|
||||||
"git.rootprojects.org/root/telebit/tunnel"
|
|
||||||
|
|
||||||
"github.com/coolaj86/certmagic"
|
"github.com/coolaj86/certmagic"
|
||||||
"github.com/denisbrodbeck/machineid"
|
"github.com/denisbrodbeck/machineid"
|
||||||
|
@ -590,7 +588,7 @@ func muxAll(
|
||||||
if "" != *apiHostname {
|
if "" != *apiHostname {
|
||||||
// this is a generic net listener
|
// this is a generic net listener
|
||||||
r := chi.NewRouter()
|
r := chi.NewRouter()
|
||||||
telebitX.RouteAdmin(*authURL, r)
|
telebit.RouteAdmin(*authURL, r)
|
||||||
apiListener := tunnel.NewListener()
|
apiListener := tunnel.NewListener()
|
||||||
go func() {
|
go func() {
|
||||||
httpsrv := &http.Server{Handler: r}
|
httpsrv := &http.Server{Handler: r}
|
||||||
|
@ -716,7 +714,7 @@ func routeSubscribersAndClients(client net.Conn) error {
|
||||||
|
|
||||||
// tryToServeName picks the server tunnel with the least connections, if any
|
// tryToServeName picks the server tunnel with the least connections, if any
|
||||||
func tryToServeName(servername string, wconn *telebit.ConnWrap) bool {
|
func tryToServeName(servername string, wconn *telebit.ConnWrap) bool {
|
||||||
srv, ok := table.GetServer(servername)
|
srv, ok := telebit.GetServer(servername)
|
||||||
if !ok || nil == srv {
|
if !ok || nil == srv {
|
||||||
if ok {
|
if ok {
|
||||||
// TODO BUG: Sometimes srv=nil & ok=true, which should not be possible
|
// TODO BUG: Sometimes srv=nil & ok=true, which should not be possible
|
||||||
|
|
|
@ -11,9 +11,9 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.rootprojects.org/root/telebit"
|
|
||||||
"git.rootprojects.org/root/telebit/internal/mgmt"
|
"git.rootprojects.org/root/telebit/internal/mgmt"
|
||||||
"git.rootprojects.org/root/telebit/internal/mgmt/authstore"
|
"git.rootprojects.org/root/telebit/internal/mgmt/authstore"
|
||||||
|
"git.rootprojects.org/root/telebit/internal/telebit"
|
||||||
|
|
||||||
"github.com/denisbrodbeck/machineid"
|
"github.com/denisbrodbeck/machineid"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
|
|
|
@ -13,9 +13,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
telebit "git.rootprojects.org/root/telebit"
|
|
||||||
tbDns01 "git.rootprojects.org/root/telebit/internal/dns01"
|
tbDns01 "git.rootprojects.org/root/telebit/internal/dns01"
|
||||||
"git.rootprojects.org/root/telebit/table"
|
"git.rootprojects.org/root/telebit/internal/telebit"
|
||||||
|
|
||||||
"github.com/coolaj86/certmagic"
|
"github.com/coolaj86/certmagic"
|
||||||
"github.com/dgrijalva/jwt-go"
|
"github.com/dgrijalva/jwt-go"
|
||||||
|
@ -219,7 +218,7 @@ func upgradeWebsocket(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
wsTun := telebit.NewWebsocketTunnel(conn)
|
wsTun := telebit.NewWebsocketTunnel(conn)
|
||||||
server := &table.SubscriberConn{
|
server := &telebit.SubscriberConn{
|
||||||
RemoteAddr: r.RemoteAddr,
|
RemoteAddr: r.RemoteAddr,
|
||||||
WSConn: conn,
|
WSConn: conn,
|
||||||
WSTun: wsTun,
|
WSTun: wsTun,
|
||||||
|
@ -243,7 +242,7 @@ func upgradeWebsocket(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Printf("a subscriber stream is done: %q\n", err)
|
fmt.Printf("a subscriber stream is done: %q\n", err)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
table.Add(server)
|
telebit.Add(server)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getACMEProvider(acmeRelay, token *string) (challenge.Provider, error) {
|
func getACMEProvider(acmeRelay, token *string) (challenge.Provider, error) {
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<title>Page Not Found</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<style>
|
|
||||||
* {
|
|
||||||
line-height: 1.2;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
html {
|
|
||||||
color: #888;
|
|
||||||
display: table;
|
|
||||||
font-family: sans-serif;
|
|
||||||
height: 100%;
|
|
||||||
text-align: center;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
display: table-cell;
|
|
||||||
vertical-align: middle;
|
|
||||||
margin: 2em auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
color: #555;
|
|
||||||
font-size: 2em;
|
|
||||||
font-weight: 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: 0 auto;
|
|
||||||
width: 280px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: 280px) {
|
|
||||||
body,
|
|
||||||
p {
|
|
||||||
width: 95%;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 1.5em;
|
|
||||||
margin: 0 0 0.3em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>Page Not Found</h1>
|
|
||||||
<p>Sorry, but the page you were trying to view does not exist.</p>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
<!-- IE needs 512+ bytes: http://blogs.msdn.com/b/ieinternals/archive/2010/08/19/http-error-pages-in-internet-explorer.aspx -->
|
|
Binary file not shown.
Before Width: | Height: | Size: 3.9 KiB |
|
@ -1,12 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Please read: https://msdn.microsoft.com/en-us/library/ie/dn455106.aspx -->
|
|
||||||
<browserconfig>
|
|
||||||
<msapplication>
|
|
||||||
<tile>
|
|
||||||
<square70x70logo src="tile.png"/>
|
|
||||||
<square150x150logo src="tile.png"/>
|
|
||||||
<wide310x150logo src="tile-wide.png"/>
|
|
||||||
<square310x310logo src="tile.png"/>
|
|
||||||
</tile>
|
|
||||||
</msapplication>
|
|
||||||
</browserconfig>
|
|
|
@ -1,15 +0,0 @@
|
||||||
<?xml version="1.0"?>
|
|
||||||
<!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
|
|
||||||
<cross-domain-policy>
|
|
||||||
<!-- Read this: https://www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html -->
|
|
||||||
|
|
||||||
<!-- Most restrictive policy: -->
|
|
||||||
<site-control permitted-cross-domain-policies="none"/>
|
|
||||||
|
|
||||||
<!-- Least restrictive policy: -->
|
|
||||||
<!--
|
|
||||||
<site-control permitted-cross-domain-policies="all"/>
|
|
||||||
<allow-access-from domain="*" to-ports="*" secure="false"/>
|
|
||||||
<allow-http-request-headers-from domain="*" headers="*" secure="false"/>
|
|
||||||
-->
|
|
||||||
</cross-domain-policy>
|
|
|
@ -1,263 +0,0 @@
|
||||||
/*! HTML5 Boilerplate v5.3.0 | MIT License | https://html5boilerplate.com/ */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* What follows is the result of much research on cross-browser styling.
|
|
||||||
* Credit left inline and big thanks to Nicolas Gallagher, Jonathan Neal,
|
|
||||||
* Kroc Camen, and the H5BP dev community and team.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
Base styles: opinionated defaults
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
html {
|
|
||||||
color: #222;
|
|
||||||
font-size: 1em;
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Remove text-shadow in selection highlight:
|
|
||||||
* https://twitter.com/miketaylr/status/12228805301
|
|
||||||
*
|
|
||||||
* These selection rule sets have to be separate.
|
|
||||||
* Customize the background color to match your design.
|
|
||||||
*/
|
|
||||||
|
|
||||||
::-moz-selection {
|
|
||||||
background: #b3d4fc;
|
|
||||||
text-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
::selection {
|
|
||||||
background: #b3d4fc;
|
|
||||||
text-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A better looking default horizontal rule
|
|
||||||
*/
|
|
||||||
|
|
||||||
hr {
|
|
||||||
display: block;
|
|
||||||
height: 1px;
|
|
||||||
border: 0;
|
|
||||||
border-top: 1px solid #ccc;
|
|
||||||
margin: 1em 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Remove the gap between audio, canvas, iframes,
|
|
||||||
* images, videos and the bottom of their containers:
|
|
||||||
* https://github.com/h5bp/html5-boilerplate/issues/440
|
|
||||||
*/
|
|
||||||
|
|
||||||
audio,
|
|
||||||
canvas,
|
|
||||||
iframe,
|
|
||||||
img,
|
|
||||||
svg,
|
|
||||||
video {
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Remove default fieldset styles.
|
|
||||||
*/
|
|
||||||
|
|
||||||
fieldset {
|
|
||||||
border: 0;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Allow only vertical resizing of textareas.
|
|
||||||
*/
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
resize: vertical;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
Browser Upgrade Prompt
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
.browserupgrade {
|
|
||||||
margin: 0.2em 0;
|
|
||||||
background: #ccc;
|
|
||||||
color: #000;
|
|
||||||
padding: 0.2em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
Author's custom styles
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
Helper classes
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Hide visually and from screen readers
|
|
||||||
*/
|
|
||||||
|
|
||||||
.hidden {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Hide only visually, but have it available for screen readers:
|
|
||||||
* http://snook.ca/archives/html_and_css/hiding-content-for-accessibility
|
|
||||||
*/
|
|
||||||
|
|
||||||
.visuallyhidden {
|
|
||||||
border: 0;
|
|
||||||
clip: rect(0 0 0 0);
|
|
||||||
height: 1px;
|
|
||||||
margin: -1px;
|
|
||||||
overflow: hidden;
|
|
||||||
padding: 0;
|
|
||||||
position: absolute;
|
|
||||||
width: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Extends the .visuallyhidden class to allow the element
|
|
||||||
* to be focusable when navigated to via the keyboard:
|
|
||||||
* https://www.drupal.org/node/897638
|
|
||||||
*/
|
|
||||||
|
|
||||||
.visuallyhidden.focusable:active,
|
|
||||||
.visuallyhidden.focusable:focus {
|
|
||||||
clip: auto;
|
|
||||||
height: auto;
|
|
||||||
margin: 0;
|
|
||||||
overflow: visible;
|
|
||||||
position: static;
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Hide visually and from screen readers, but maintain layout
|
|
||||||
*/
|
|
||||||
|
|
||||||
.invisible {
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Clearfix: contain floats
|
|
||||||
*
|
|
||||||
* For modern browsers
|
|
||||||
* 1. The space content is one way to avoid an Opera bug when the
|
|
||||||
* `contenteditable` attribute is included anywhere else in the document.
|
|
||||||
* Otherwise it causes space to appear at the top and bottom of elements
|
|
||||||
* that receive the `clearfix` class.
|
|
||||||
* 2. The use of `table` rather than `block` is only necessary if using
|
|
||||||
* `:before` to contain the top-margins of child elements.
|
|
||||||
*/
|
|
||||||
|
|
||||||
.clearfix:before,
|
|
||||||
.clearfix:after {
|
|
||||||
content: " "; /* 1 */
|
|
||||||
display: table; /* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
.clearfix:after {
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
EXAMPLE Media Queries for Responsive Design.
|
|
||||||
These examples override the primary ('mobile first') styles.
|
|
||||||
Modify as content requires.
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
@media only screen and (min-width: 35em) {
|
|
||||||
/* Style adjustments for viewports that meet the condition */
|
|
||||||
}
|
|
||||||
|
|
||||||
@media print, (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 1.25dppx), (min-resolution: 120dpi) {
|
|
||||||
/* Style adjustments for high resolution devices */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==========================================================================
|
|
||||||
Print styles.
|
|
||||||
Inlined to avoid the additional HTTP request:
|
|
||||||
http://www.phpied.com/delay-loading-your-print-css/
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
@media print {
|
|
||||||
*,
|
|
||||||
*:before,
|
|
||||||
*:after,
|
|
||||||
*:first-letter,
|
|
||||||
*:first-line {
|
|
||||||
background: transparent !important;
|
|
||||||
color: #000 !important; /* Black prints faster:
|
|
||||||
http://www.sanbeiji.com/archives/953 */
|
|
||||||
box-shadow: none !important;
|
|
||||||
text-shadow: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
a,
|
|
||||||
a:visited {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
a[href]:after {
|
|
||||||
content: " (" attr(href) ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
abbr[title]:after {
|
|
||||||
content: " (" attr(title) ")";
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Don't show links that are fragment identifiers,
|
|
||||||
* or use the `javascript:` pseudo protocol
|
|
||||||
*/
|
|
||||||
|
|
||||||
a[href^="#"]:after,
|
|
||||||
a[href^="javascript:"]:after {
|
|
||||||
content: "";
|
|
||||||
}
|
|
||||||
|
|
||||||
pre,
|
|
||||||
blockquote {
|
|
||||||
border: 1px solid #999;
|
|
||||||
page-break-inside: avoid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Printing Tables:
|
|
||||||
* http://css-discuss.incutio.com/wiki/Printing_Tables
|
|
||||||
*/
|
|
||||||
|
|
||||||
thead {
|
|
||||||
display: table-header-group;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr,
|
|
||||||
img {
|
|
||||||
page-break-inside: avoid;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
max-width: 100% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
p,
|
|
||||||
h2,
|
|
||||||
h3 {
|
|
||||||
orphans: 3;
|
|
||||||
widows: 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2,
|
|
||||||
h3 {
|
|
||||||
page-break-after: avoid;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,424 +0,0 @@
|
||||||
/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Set default font family to sans-serif.
|
|
||||||
* 2. Prevent iOS and IE text size adjust after device orientation change,
|
|
||||||
* without disabling user zoom.
|
|
||||||
*/
|
|
||||||
|
|
||||||
html {
|
|
||||||
font-family: sans-serif; /* 1 */
|
|
||||||
-ms-text-size-adjust: 100%; /* 2 */
|
|
||||||
-webkit-text-size-adjust: 100%; /* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove default margin.
|
|
||||||
*/
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* HTML5 display definitions
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct `block` display not defined for any HTML5 element in IE 8/9.
|
|
||||||
* Correct `block` display not defined for `details` or `summary` in IE 10/11
|
|
||||||
* and Firefox.
|
|
||||||
* Correct `block` display not defined for `main` in IE 11.
|
|
||||||
*/
|
|
||||||
|
|
||||||
article,
|
|
||||||
aside,
|
|
||||||
details,
|
|
||||||
figcaption,
|
|
||||||
figure,
|
|
||||||
footer,
|
|
||||||
header,
|
|
||||||
hgroup,
|
|
||||||
main,
|
|
||||||
menu,
|
|
||||||
nav,
|
|
||||||
section,
|
|
||||||
summary {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Correct `inline-block` display not defined in IE 8/9.
|
|
||||||
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
|
|
||||||
*/
|
|
||||||
|
|
||||||
audio,
|
|
||||||
canvas,
|
|
||||||
progress,
|
|
||||||
video {
|
|
||||||
display: inline-block; /* 1 */
|
|
||||||
vertical-align: baseline; /* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prevent modern browsers from displaying `audio` without controls.
|
|
||||||
* Remove excess height in iOS 5 devices.
|
|
||||||
*/
|
|
||||||
|
|
||||||
audio:not([controls]) {
|
|
||||||
display: none;
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address `[hidden]` styling not present in IE 8/9/10.
|
|
||||||
* Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
|
|
||||||
*/
|
|
||||||
|
|
||||||
[hidden],
|
|
||||||
template {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Links
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove the gray background color from active links in IE 10.
|
|
||||||
*/
|
|
||||||
|
|
||||||
a {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Improve readability of focused elements when they are also in an
|
|
||||||
* active/hover state.
|
|
||||||
*/
|
|
||||||
|
|
||||||
a:active,
|
|
||||||
a:hover {
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Text-level semantics
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
|
|
||||||
*/
|
|
||||||
|
|
||||||
abbr[title] {
|
|
||||||
border-bottom: 1px dotted;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
|
|
||||||
*/
|
|
||||||
|
|
||||||
b,
|
|
||||||
strong {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address styling not present in Safari and Chrome.
|
|
||||||
*/
|
|
||||||
|
|
||||||
dfn {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address variable `h1` font-size and margin within `section` and `article`
|
|
||||||
* contexts in Firefox 4+, Safari, and Chrome.
|
|
||||||
*/
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 2em;
|
|
||||||
margin: 0.67em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address styling not present in IE 8/9.
|
|
||||||
*/
|
|
||||||
|
|
||||||
mark {
|
|
||||||
background: #ff0;
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address inconsistent and variable font size in all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
small {
|
|
||||||
font-size: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
sub,
|
|
||||||
sup {
|
|
||||||
font-size: 75%;
|
|
||||||
line-height: 0;
|
|
||||||
position: relative;
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
|
|
||||||
sup {
|
|
||||||
top: -0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub {
|
|
||||||
bottom: -0.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Embedded content
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove border when inside `a` element in IE 8/9/10.
|
|
||||||
*/
|
|
||||||
|
|
||||||
img {
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Correct overflow not hidden in IE 9/10/11.
|
|
||||||
*/
|
|
||||||
|
|
||||||
svg:not(:root) {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Grouping content
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address margin not present in IE 8/9 and Safari.
|
|
||||||
*/
|
|
||||||
|
|
||||||
figure {
|
|
||||||
margin: 1em 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address differences between Firefox and other browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
hr {
|
|
||||||
box-sizing: content-box;
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Contain overflow in all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
pre {
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address odd `em`-unit font size rendering in all browsers.
|
|
||||||
*/
|
|
||||||
|
|
||||||
code,
|
|
||||||
kbd,
|
|
||||||
pre,
|
|
||||||
samp {
|
|
||||||
font-family: monospace, monospace;
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Forms
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Known limitation: by default, Chrome and Safari on OS X allow very limited
|
|
||||||
* styling of `select`, unless a `border` property is set.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Correct color not being inherited.
|
|
||||||
* Known issue: affects color of disabled elements.
|
|
||||||
* 2. Correct font properties not being inherited.
|
|
||||||
* 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button,
|
|
||||||
input,
|
|
||||||
optgroup,
|
|
||||||
select,
|
|
||||||
textarea {
|
|
||||||
color: inherit; /* 1 */
|
|
||||||
font: inherit; /* 2 */
|
|
||||||
margin: 0; /* 3 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address `overflow` set to `hidden` in IE 8/9/10/11.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button {
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address inconsistent `text-transform` inheritance for `button` and `select`.
|
|
||||||
* All other form control elements do not inherit `text-transform` values.
|
|
||||||
* Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
|
|
||||||
* Correct `select` style inheritance in Firefox.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button,
|
|
||||||
select {
|
|
||||||
text-transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
|
|
||||||
* and `video` controls.
|
|
||||||
* 2. Correct inability to style clickable `input` types in iOS.
|
|
||||||
* 3. Improve usability and consistency of cursor style between image-type
|
|
||||||
* `input` and others.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button,
|
|
||||||
html input[type="button"], /* 1 */
|
|
||||||
input[type="reset"],
|
|
||||||
input[type="submit"] {
|
|
||||||
-webkit-appearance: button; /* 2 */
|
|
||||||
cursor: pointer; /* 3 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Re-set default cursor for disabled elements.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button[disabled],
|
|
||||||
html input[disabled] {
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove inner padding and border in Firefox 4+.
|
|
||||||
*/
|
|
||||||
|
|
||||||
button::-moz-focus-inner,
|
|
||||||
input::-moz-focus-inner {
|
|
||||||
border: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
|
|
||||||
* the UA stylesheet.
|
|
||||||
*/
|
|
||||||
|
|
||||||
input {
|
|
||||||
line-height: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* It's recommended that you don't attempt to style these elements.
|
|
||||||
* Firefox's implementation doesn't respect box-sizing, padding, or width.
|
|
||||||
*
|
|
||||||
* 1. Address box sizing set to `content-box` in IE 8/9/10.
|
|
||||||
* 2. Remove excess padding in IE 8/9/10.
|
|
||||||
*/
|
|
||||||
|
|
||||||
input[type="checkbox"],
|
|
||||||
input[type="radio"] {
|
|
||||||
box-sizing: border-box; /* 1 */
|
|
||||||
padding: 0; /* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
|
|
||||||
* `font-size` values of the `input`, it causes the cursor style of the
|
|
||||||
* decrement button to change from `default` to `text`.
|
|
||||||
*/
|
|
||||||
|
|
||||||
input[type="number"]::-webkit-inner-spin-button,
|
|
||||||
input[type="number"]::-webkit-outer-spin-button {
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Address `appearance` set to `searchfield` in Safari and Chrome.
|
|
||||||
* 2. Address `box-sizing` set to `border-box` in Safari and Chrome.
|
|
||||||
*/
|
|
||||||
|
|
||||||
input[type="search"] {
|
|
||||||
-webkit-appearance: textfield; /* 1 */
|
|
||||||
box-sizing: content-box; /* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
|
|
||||||
* Safari (but not Chrome) clips the cancel button when the search input has
|
|
||||||
* padding (and `textfield` appearance).
|
|
||||||
*/
|
|
||||||
|
|
||||||
input[type="search"]::-webkit-search-cancel-button,
|
|
||||||
input[type="search"]::-webkit-search-decoration {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Define consistent border, margin, and padding.
|
|
||||||
*/
|
|
||||||
|
|
||||||
fieldset {
|
|
||||||
border: 1px solid #c0c0c0;
|
|
||||||
margin: 0 2px;
|
|
||||||
padding: 0.35em 0.625em 0.75em;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 1. Correct `color` not being inherited in IE 8/9/10/11.
|
|
||||||
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
|
|
||||||
*/
|
|
||||||
|
|
||||||
legend {
|
|
||||||
border: 0; /* 1 */
|
|
||||||
padding: 0; /* 2 */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove default vertical scrollbar in IE 8/9/10/11.
|
|
||||||
*/
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Don't inherit the `font-weight` (applied by a rule above).
|
|
||||||
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
|
|
||||||
*/
|
|
||||||
|
|
||||||
optgroup {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tables
|
|
||||||
========================================================================== */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove most spacing between table cells.
|
|
||||||
*/
|
|
||||||
|
|
||||||
table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
border-spacing: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
td,
|
|
||||||
th {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
Binary file not shown.
Before Width: | Height: | Size: 766 B |
|
@ -1,15 +0,0 @@
|
||||||
# humanstxt.org/
|
|
||||||
# The humans responsible & technology colophon
|
|
||||||
|
|
||||||
# TEAM
|
|
||||||
|
|
||||||
<name> -- <role> -- <twitter>
|
|
||||||
|
|
||||||
# THANKS
|
|
||||||
|
|
||||||
<name>
|
|
||||||
|
|
||||||
# TECHNOLOGY COLOPHON
|
|
||||||
|
|
||||||
CSS3, HTML5
|
|
||||||
Apache Server Configs, jQuery, Modernizr, Normalize.css
|
|
|
@ -1,97 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html class="no-js" lang="">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta http-equiv="x-ua-compatible" content="ie=edge" />
|
|
||||||
<title></title>
|
|
||||||
<meta name="description" content="" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
|
|
||||||
<link rel="apple-touch-icon" href="apple-touch-icon.png" />
|
|
||||||
<!-- Place favicon.ico in the root directory -->
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="css/normalize.css" />
|
|
||||||
<link rel="stylesheet" href="css/main.css" />
|
|
||||||
<script src="js/vendor/modernizr-2.8.3.min.js"></script>
|
|
||||||
<base href="/" />
|
|
||||||
</head>
|
|
||||||
<body ng-app="rvpnApp">
|
|
||||||
<!--[if lt IE 8]>
|
|
||||||
<p class="browserupgrade">
|
|
||||||
You are using an <strong>outdated</strong> browser. Please
|
|
||||||
<a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.
|
|
||||||
</p>
|
|
||||||
<![endif]-->
|
|
||||||
|
|
||||||
<!-- Admin GUI Begins Here -->
|
|
||||||
<header class="bs-docs-nav navbar navbar-static-top" id="top">
|
|
||||||
<div class="container">
|
|
||||||
<div class="navbar-header">
|
|
||||||
<a href="/admin/index.html" target="_parent" class="navbar-brand">RVPN Admin</a>
|
|
||||||
</div>
|
|
||||||
<nav class="collapse navbar-collapse" id="bs-navbar">
|
|
||||||
<ul class="nav navbar-nav">
|
|
||||||
<li><a href="/admin/status">Status</a></li>
|
|
||||||
<li><a href="/admin/servers">Servers</a></li>
|
|
||||||
<li><a href="/admin/#domains">Domains</a></li>
|
|
||||||
<li><a href="/admin/#connections">Connections</a></li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<ul class="nav navbar-nav navbar-right">
|
|
||||||
<li><a href="#">Help</a></li>
|
|
||||||
<li><a href="#">Login</a></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div ng-view></div>
|
|
||||||
|
|
||||||
<script src="https://code.jquery.com/jquery-1.12.0.min.js"></script>
|
|
||||||
<script>
|
|
||||||
window.jQuery || document.write('<script src="admin/js/vendor/jquery-1.12.0.min.js"><\/script>');
|
|
||||||
</script>
|
|
||||||
<script src="admin/js/plugins.js"></script>
|
|
||||||
<script src="admin/js/main.js"></script>
|
|
||||||
|
|
||||||
<!-- Google Analytics: change UA-XXXXX-X to be your site's ID. -->
|
|
||||||
<script>
|
|
||||||
(function (b, o, i, l, e, r) {
|
|
||||||
b.GoogleAnalyticsObject = l;
|
|
||||||
b[l] ||
|
|
||||||
(b[l] = function () {
|
|
||||||
(b[l].q = b[l].q || []).push(arguments);
|
|
||||||
});
|
|
||||||
b[l].l = +new Date();
|
|
||||||
e = o.createElement(i);
|
|
||||||
r = o.getElementsByTagName(i)[0];
|
|
||||||
e.src = "https://www.google-analytics.com/analytics.js";
|
|
||||||
r.parentNode.insertBefore(e, r);
|
|
||||||
})(window, document, "script", "ga");
|
|
||||||
ga("create", "UA-XXXXX-X", "auto");
|
|
||||||
ga("send", "pageview");
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
|
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.js"></script>
|
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular-route.js"></script>
|
|
||||||
<link
|
|
||||||
rel="stylesheet"
|
|
||||||
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
|
|
||||||
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
|
|
||||||
crossorigin="anonymous"
|
|
||||||
/>
|
|
||||||
<link
|
|
||||||
rel="stylesheet"
|
|
||||||
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css"
|
|
||||||
integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp"
|
|
||||||
crossorigin="anonymous"
|
|
||||||
/>
|
|
||||||
<script
|
|
||||||
src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"
|
|
||||||
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
|
|
||||||
crossorigin="anonymous"
|
|
||||||
></script>
|
|
||||||
<script src="/admin/js/vendor/filter.js"></script>
|
|
||||||
<script src="/admin/js/app.js"></script>
|
|
||||||
</html>
|
|
|
@ -1,129 +0,0 @@
|
||||||
console.log("app.sh startup");
|
|
||||||
|
|
||||||
var app = angular.module("rvpnApp", ["ngRoute", "angular-duration-format"]);
|
|
||||||
|
|
||||||
app.config(function ($routeProvider, $locationProvider) {
|
|
||||||
$routeProvider
|
|
||||||
|
|
||||||
.when("/admin/status/", {
|
|
||||||
templateUrl: "admin/partials/status.html"
|
|
||||||
})
|
|
||||||
|
|
||||||
.when("/admin/index.html", {
|
|
||||||
templateUrl: "admin/partials/servers.html"
|
|
||||||
})
|
|
||||||
|
|
||||||
.when("/admin/servers/", {
|
|
||||||
templateUrl: "admin/partials/servers.html"
|
|
||||||
})
|
|
||||||
|
|
||||||
.when("/admin/#domains", {
|
|
||||||
templateUrl: "green.htm"
|
|
||||||
})
|
|
||||||
|
|
||||||
.when("/blue", {
|
|
||||||
templateUrl: "blue.htm"
|
|
||||||
});
|
|
||||||
$locationProvider.html5Mode(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
app.filter("bytes", function () {
|
|
||||||
return function (bytes, precision) {
|
|
||||||
if (isNaN(parseFloat(bytes)) || !isFinite(bytes)) return "-";
|
|
||||||
if (typeof precision === "undefined") precision = 1;
|
|
||||||
var units = ["bytes", "kB", "MB", "GB", "TB", "PB"],
|
|
||||||
number = Math.floor(Math.log(bytes) / Math.log(1024));
|
|
||||||
return (bytes / Math.pow(1024, Math.floor(number))).toFixed(precision) + " " + units[number];
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
app.filter("hfcduration", function () {
|
|
||||||
return function (duration, precision) {
|
|
||||||
remain = duration;
|
|
||||||
duration_day = 24 * 60 * 60;
|
|
||||||
duration_hour = 60 * 60;
|
|
||||||
duration_minute = 60;
|
|
||||||
duration_str = "";
|
|
||||||
|
|
||||||
days = Math.floor(remain / duration_day);
|
|
||||||
if (days > 0) {
|
|
||||||
remain = remain - days * duration_day;
|
|
||||||
duration_str = duration_str + days + "d";
|
|
||||||
}
|
|
||||||
|
|
||||||
hours = Math.floor(remain / duration_hour);
|
|
||||||
if (hours > 0) {
|
|
||||||
remain = remain - hours * duration_hour;
|
|
||||||
duration_str = duration_str + hours + "h";
|
|
||||||
}
|
|
||||||
|
|
||||||
mins = Math.floor(remain / duration_minute);
|
|
||||||
if (mins > 0) {
|
|
||||||
remain = remain - mins * duration_minute;
|
|
||||||
duration_str = duration_str + mins + "m";
|
|
||||||
}
|
|
||||||
|
|
||||||
secs = Math.floor(remain);
|
|
||||||
duration_str = duration_str + secs + "s";
|
|
||||||
|
|
||||||
return duration_str;
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
app.controller("statusController", function ($scope, $http) {
|
|
||||||
console.log("statusController");
|
|
||||||
$scope.status_search = "";
|
|
||||||
|
|
||||||
var api = "/api/org.rootprojects.tunnel/status";
|
|
||||||
|
|
||||||
$scope.updateView = function () {
|
|
||||||
$http.get(api).then(function (response) {
|
|
||||||
console.log(response);
|
|
||||||
data = response.data;
|
|
||||||
if (data.error == "ok") {
|
|
||||||
$scope.status = data.result;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.updateView();
|
|
||||||
});
|
|
||||||
|
|
||||||
app.controller("serverController", function ($scope, $http) {
|
|
||||||
$scope.servers = [];
|
|
||||||
$scope.servers_search = "";
|
|
||||||
$scope.servers_trigger_details = [];
|
|
||||||
$scope.filtered;
|
|
||||||
|
|
||||||
var api = "/api/org.rootprojects.tunnel/servers";
|
|
||||||
|
|
||||||
$scope.updateView = function () {
|
|
||||||
$http.get(api).then(function (response) {
|
|
||||||
//console.log(response);
|
|
||||||
data = response.data;
|
|
||||||
if (data.error == "ok") {
|
|
||||||
$scope.servers = data.result.servers;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.triggerDetail = function (id) {
|
|
||||||
//console.log("triggerDetail ", id, $scope.servers_trigger_details[id])
|
|
||||||
if ($scope.servers_trigger_details[id] == true) {
|
|
||||||
$scope.servers_trigger_details[id] = false;
|
|
||||||
} else {
|
|
||||||
$scope.servers_trigger_details[id] = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.checkDetail = function (id) {
|
|
||||||
//console.log("checkDetail ", id, $scope.servers_trigger_details[id])
|
|
||||||
if ($scope.servers_trigger_details[id] == true) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.updateView();
|
|
||||||
});
|
|
|
@ -1,44 +0,0 @@
|
||||||
// Avoid `console` errors in browsers that lack a console.
|
|
||||||
(function () {
|
|
||||||
var method;
|
|
||||||
var noop = function () {};
|
|
||||||
var methods = [
|
|
||||||
"assert",
|
|
||||||
"clear",
|
|
||||||
"count",
|
|
||||||
"debug",
|
|
||||||
"dir",
|
|
||||||
"dirxml",
|
|
||||||
"error",
|
|
||||||
"exception",
|
|
||||||
"group",
|
|
||||||
"groupCollapsed",
|
|
||||||
"groupEnd",
|
|
||||||
"info",
|
|
||||||
"log",
|
|
||||||
"markTimeline",
|
|
||||||
"profile",
|
|
||||||
"profileEnd",
|
|
||||||
"table",
|
|
||||||
"time",
|
|
||||||
"timeEnd",
|
|
||||||
"timeline",
|
|
||||||
"timelineEnd",
|
|
||||||
"timeStamp",
|
|
||||||
"trace",
|
|
||||||
"warn"
|
|
||||||
];
|
|
||||||
var length = methods.length;
|
|
||||||
var console = (window.console = window.console || {});
|
|
||||||
|
|
||||||
while (length--) {
|
|
||||||
method = methods[length];
|
|
||||||
|
|
||||||
// Only stub undefined methods.
|
|
||||||
if (!console[method]) {
|
|
||||||
console[method] = noop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
|
||||||
// Place any jQuery/helper plugins in here.
|
|
|
@ -1,165 +0,0 @@
|
||||||
// ### filter.js >>
|
|
||||||
|
|
||||||
angular.module("angular-duration-format.filter", []).filter("duration", function () {
|
|
||||||
var DURATION_FORMATS_SPLIT = /((?:[^ydhms']+)|(?:'(?:[^']|'')*')|(?:y+|d+|h+|m+|s+))(.*)/;
|
|
||||||
var DURATION_FORMATS = {
|
|
||||||
y: {
|
|
||||||
// years
|
|
||||||
// "longer" years are not supported
|
|
||||||
value: 365 * 24 * 60 * 60 * 1000
|
|
||||||
},
|
|
||||||
yy: {
|
|
||||||
value: "y",
|
|
||||||
pad: 2
|
|
||||||
},
|
|
||||||
d: {
|
|
||||||
// days
|
|
||||||
value: 24 * 60 * 60 * 1000
|
|
||||||
},
|
|
||||||
dd: {
|
|
||||||
value: "d",
|
|
||||||
pad: 2
|
|
||||||
},
|
|
||||||
h: {
|
|
||||||
// hours
|
|
||||||
value: 60 * 60 * 1000
|
|
||||||
},
|
|
||||||
hh: {
|
|
||||||
// padded hours
|
|
||||||
value: "h",
|
|
||||||
pad: 2
|
|
||||||
},
|
|
||||||
m: {
|
|
||||||
// minutes
|
|
||||||
value: 60 * 1000
|
|
||||||
},
|
|
||||||
mm: {
|
|
||||||
// padded minutes
|
|
||||||
value: "m",
|
|
||||||
pad: 2
|
|
||||||
},
|
|
||||||
s: {
|
|
||||||
// seconds
|
|
||||||
value: 1000
|
|
||||||
},
|
|
||||||
ss: {
|
|
||||||
// padded seconds
|
|
||||||
value: "s",
|
|
||||||
pad: 2
|
|
||||||
},
|
|
||||||
sss: {
|
|
||||||
// milliseconds
|
|
||||||
value: 1
|
|
||||||
},
|
|
||||||
ssss: {
|
|
||||||
// padded milliseconds
|
|
||||||
value: "sss",
|
|
||||||
pad: 4
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function _parseFormat(string) {
|
|
||||||
// @inspiration AngularJS date filter
|
|
||||||
var parts = [];
|
|
||||||
var format = string ? string.toString() : "";
|
|
||||||
|
|
||||||
while (format) {
|
|
||||||
var match = DURATION_FORMATS_SPLIT.exec(format);
|
|
||||||
|
|
||||||
if (match) {
|
|
||||||
parts = parts.concat(match.slice(1));
|
|
||||||
|
|
||||||
format = parts.pop();
|
|
||||||
} else {
|
|
||||||
parts.push(format);
|
|
||||||
|
|
||||||
format = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return parts;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _formatDuration(timestamp, format) {
|
|
||||||
var text = "";
|
|
||||||
var values = {};
|
|
||||||
|
|
||||||
format
|
|
||||||
.filter(function (format) {
|
|
||||||
// filter only value parts of format
|
|
||||||
return DURATION_FORMATS.hasOwnProperty(format);
|
|
||||||
})
|
|
||||||
.map(function (format) {
|
|
||||||
// get formats with values only
|
|
||||||
var config = DURATION_FORMATS[format];
|
|
||||||
|
|
||||||
if (config.hasOwnProperty("pad")) {
|
|
||||||
return config.value;
|
|
||||||
} else {
|
|
||||||
return format;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.filter(function (format, index, arr) {
|
|
||||||
// remove duplicates
|
|
||||||
return arr.indexOf(format) === index;
|
|
||||||
})
|
|
||||||
.map(function (format) {
|
|
||||||
// get format configurations with values
|
|
||||||
return angular.extend(
|
|
||||||
{
|
|
||||||
name: format
|
|
||||||
},
|
|
||||||
DURATION_FORMATS[format]
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.sort(function (a, b) {
|
|
||||||
// sort formats descending by value
|
|
||||||
return b.value - a.value;
|
|
||||||
})
|
|
||||||
.forEach(function (format) {
|
|
||||||
// create values for format parts
|
|
||||||
var value = (values[format.name] = Math.floor(timestamp / format.value));
|
|
||||||
|
|
||||||
timestamp = timestamp - value * format.value;
|
|
||||||
});
|
|
||||||
|
|
||||||
format.forEach(function (part) {
|
|
||||||
var format = DURATION_FORMATS[part];
|
|
||||||
|
|
||||||
if (format) {
|
|
||||||
var value = values[format.value];
|
|
||||||
|
|
||||||
text += format.hasOwnProperty("pad")
|
|
||||||
? _padNumber(value, Math.max(format.pad, value.toString().length))
|
|
||||||
: values[part];
|
|
||||||
} else {
|
|
||||||
text += part.replace(/(^'|'$)/g, "").replace(/''/g, "'");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _padNumber(number, len) {
|
|
||||||
return (new Array(len + 1).join("0") + number).slice(-len);
|
|
||||||
}
|
|
||||||
|
|
||||||
return function (value, format) {
|
|
||||||
var parsedValue = parseFloat(value, 10);
|
|
||||||
var parsedFormat = _parseFormat(format);
|
|
||||||
|
|
||||||
if (isNaN(parsedValue) || parsedFormat.length === 0) {
|
|
||||||
return value;
|
|
||||||
} else {
|
|
||||||
return _formatDuration(parsedValue, parsedFormat);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// ### << filter.js
|
|
||||||
|
|
||||||
// ### main.js >>
|
|
||||||
|
|
||||||
angular.module("angular-duration-format", ["angular-duration-format.filter"]);
|
|
||||||
|
|
||||||
// ### << main.js
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,98 +0,0 @@
|
||||||
<div class="panel panel-default" data-ng-controller="serverController">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<div class="panel-title">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
Servers
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<form class="form-inline pull-right">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="search">Search:</label>
|
|
||||||
<input type="text" class="form-control" id="search" data-ng-model="servers_search" />
|
|
||||||
</div>
|
|
||||||
<button type="button" title="Refresh" class="btn btn-default" aria-label="Refresh">
|
|
||||||
<span
|
|
||||||
class="glyphicon glyphicon-refresh"
|
|
||||||
title="Refresh"
|
|
||||||
aria-hidden="false"
|
|
||||||
ng-click="updateView()"
|
|
||||||
></span>
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="panel-body">
|
|
||||||
<table class="table table-striped table-bordered">
|
|
||||||
<th width="3%">ID</th>
|
|
||||||
<th width="10%">Name</th>
|
|
||||||
<th width="10%">Address</th>
|
|
||||||
<th width="10%">Xfer (in/out)</th>
|
|
||||||
<th width="10%">Req/Resp</th>
|
|
||||||
<th width="5%">Duration</th>
|
|
||||||
<th width="5%">State</th>
|
|
||||||
<th width="5%">Idle</th>
|
|
||||||
<th width="1%">
|
|
||||||
<center><span class="glyphicon glyphicon-option-vertical" aria-hidden="true"></span></center>
|
|
||||||
</th>
|
|
||||||
|
|
||||||
<tr ng-repeat="s in servers | filter:servers_search | orderBy:'server_id'">
|
|
||||||
<td>{{ s.server_id }}</td>
|
|
||||||
<td>{{ s.server_name }}</td>
|
|
||||||
<td>
|
|
||||||
{{ s.source_address }}
|
|
||||||
<div ng-hide="checkDetail(s.server_id)">
|
|
||||||
domains({{ s.domains.length}})
|
|
||||||
<div ng-repeat="d in s.domains | orderBy:'domain_name'">
|
|
||||||
   {{ d.domain_name }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ s.bytes_in | bytes }}/{{ s.bytes_out | bytes }}
|
|
||||||
<div ng-hide="checkDetail(s.server_id)">
|
|
||||||
 
|
|
||||||
<div ng-repeat="d in s.domains | orderBy:'domain_name'">
|
|
||||||
   {{ d.bytes_in | bytes }}/{{ d.bytes_out | bytes }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ s.requests }}/{{ s.responses }}
|
|
||||||
<div ng-hide="checkDetail(s.server_id)">
|
|
||||||
 
|
|
||||||
<div ng-repeat="d in s.domains | orderBy:'domain_name'">
|
|
||||||
   {{ d.requests }}/{{ d.responses }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td>{{ s.duration | hfcduration }}</td>
|
|
||||||
<td>{{ s.server_state }}</td>
|
|
||||||
<td>{{ s.idle | hfcduration }}</td>
|
|
||||||
<td>
|
|
||||||
<span
|
|
||||||
class="glyphicon glyphicon-zoom-in"
|
|
||||||
title="Detail"
|
|
||||||
aria-hidden="false"
|
|
||||||
ng-click="triggerDetail(s.server_id)"
|
|
||||||
></span>
|
|
||||||
<div ng-hide="checkDetail(s.server_id)">
|
|
||||||
 
|
|
||||||
<div ng-repeat="d in s.domains | orderBy:'domain_name'">
|
|
||||||
<span
|
|
||||||
class="glyphicon glyphicon-zoom-in"
|
|
||||||
title="Detail"
|
|
||||||
aria-hidden="false"
|
|
||||||
ng-click="triggerDetail(s.server_id+d.domain_name)"
|
|
||||||
></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,52 +0,0 @@
|
||||||
<div class="panel panel-default" data-ng-controller="statusController">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<div class="panel-title">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
Status
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<form class="form-inline pull-right">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="search">Search:</label>
|
|
||||||
<input type="text" class="form-control" id="search" data-ng-model="servers_search" />
|
|
||||||
</div>
|
|
||||||
<button type="button" title="Refresh" class="btn btn-default" aria-label="Refresh">
|
|
||||||
<span
|
|
||||||
class="glyphicon glyphicon-refresh"
|
|
||||||
title="Refresh"
|
|
||||||
aria-hidden="false"
|
|
||||||
ng-click="updateView()"
|
|
||||||
></span>
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-4"></div>
|
|
||||||
<div class="col-md-8">Server Name: {{ status.name }} (Uptime: {{ status.uptime | hfcduration }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-4"></div>
|
|
||||||
<div class="col-md-8">Administrative Domain: {{ status.admin_domain }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-4"></div>
|
|
||||||
<div class="col-md-8">Server Domain: {{ status.wss_domain }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-4"></div>
|
|
||||||
<div class="col-md-8">Default LB Method: {{ status.loadbalance_default_method }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-4"></div>
|
|
||||||
<div class="col-md-8">
|
|
||||||
Deadtime: dwell:{{ status.dead_time.dwell}} idle:{{ status.dead_time.idle}} cancel:{{
|
|
||||||
status.dead_time.cancel_check}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
|
@ -1,5 +0,0 @@
|
||||||
# www.robotstxt.org/
|
|
||||||
|
|
||||||
# Allow crawling of all content
|
|
||||||
User-agent: *
|
|
||||||
Disallow:
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.4 KiB |
|
@ -7,9 +7,9 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
telebit "git.rootprojects.org/root/telebit"
|
"git.rootprojects.org/root/telebit/internal/dbg"
|
||||||
"git.rootprojects.org/root/telebit/dbg"
|
|
||||||
"git.rootprojects.org/root/telebit/internal/mgmt/authstore"
|
"git.rootprojects.org/root/telebit/internal/mgmt/authstore"
|
||||||
|
"git.rootprojects.org/root/telebit/internal/telebit"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SuccessResponse struct {
|
type SuccessResponse struct {
|
||||||
|
|
|
@ -9,7 +9,8 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.rootprojects.org/root/telebit/dbg"
|
"git.rootprojects.org/root/telebit/internal/dbg"
|
||||||
|
|
||||||
jwt "github.com/dgrijalva/jwt-go"
|
jwt "github.com/dgrijalva/jwt-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.rootprojects.org/root/telebit/files"
|
"git.rootprojects.org/root/telebit/assets/files"
|
||||||
|
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
// pq injects itself into sql as 'postgres'
|
// pq injects itself into sql as 'postgres'
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.rootprojects.org/root/telebit/dbg"
|
"git.rootprojects.org/root/telebit/internal/dbg"
|
||||||
"git.rootprojects.org/root/telebit/internal/mgmt/authstore"
|
"git.rootprojects.org/root/telebit/internal/mgmt/authstore"
|
||||||
|
|
||||||
"github.com/dgrijalva/jwt-go"
|
"github.com/dgrijalva/jwt-go"
|
||||||
|
|
|
@ -13,17 +13,15 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.rootprojects.org/root/telebit"
|
"git.rootprojects.org/root/telebit/assets/admin"
|
||||||
"git.rootprojects.org/root/telebit/admin"
|
"git.rootprojects.org/root/telebit/internal/dbg"
|
||||||
"git.rootprojects.org/root/telebit/dbg"
|
|
||||||
"git.rootprojects.org/root/telebit/table"
|
|
||||||
|
|
||||||
"github.com/go-chi/chi"
|
"github.com/go-chi/chi"
|
||||||
"github.com/go-chi/chi/middleware"
|
"github.com/go-chi/chi/middleware"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
var authorizer telebit.Authorizer
|
var authorizer Authorizer
|
||||||
|
|
||||||
// RouteAdmin sets up the API, including the Mgmt proxy and ACME relay
|
// RouteAdmin sets up the API, including the Mgmt proxy and ACME relay
|
||||||
func RouteAdmin(authURL string, r chi.Router) {
|
func RouteAdmin(authURL string, r chi.Router) {
|
||||||
|
@ -134,7 +132,7 @@ type SubscriberStatus struct {
|
||||||
|
|
||||||
func getAllSubscribers(w http.ResponseWriter, r *http.Request) {
|
func getAllSubscribers(w http.ResponseWriter, r *http.Request) {
|
||||||
statuses := []*SubscriberStatus{}
|
statuses := []*SubscriberStatus{}
|
||||||
table.Servers.Range(func(key, value interface{}) bool {
|
Servers.Range(func(key, value interface{}) bool {
|
||||||
srvMap := value.(*sync.Map)
|
srvMap := value.(*sync.Map)
|
||||||
status := getSubscribersHelper(srvMap)
|
status := getSubscribersHelper(srvMap)
|
||||||
statuses = append(statuses, status)
|
statuses = append(statuses, status)
|
||||||
|
@ -160,7 +158,7 @@ func getSubscribers(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var srvMap *sync.Map
|
var srvMap *sync.Map
|
||||||
srvMapX, ok := table.Servers.Load(subject)
|
srvMapX, ok := Servers.Load(subject)
|
||||||
if ok {
|
if ok {
|
||||||
srvMap = srvMapX.(*sync.Map)
|
srvMap = srvMapX.(*sync.Map)
|
||||||
statuses.Subscribers = append(statuses.Subscribers, getSubscribersHelper(srvMap))
|
statuses.Subscribers = append(statuses.Subscribers, getSubscribersHelper(srvMap))
|
||||||
|
@ -179,7 +177,7 @@ func getSubscribersHelper(srvMap *sync.Map) *SubscriberStatus {
|
||||||
|
|
||||||
srvMap.Range(func(k, v interface{}) bool {
|
srvMap.Range(func(k, v interface{}) bool {
|
||||||
status.Sockets = append(status.Sockets, k.(string))
|
status.Sockets = append(status.Sockets, k.(string))
|
||||||
srv := v.(*table.SubscriberConn)
|
srv := v.(*SubscriberConn)
|
||||||
if nil == status.Since || srv.Since.Sub(*status.Since) < 0 {
|
if nil == status.Since || srv.Since.Sub(*status.Since) < 0 {
|
||||||
copied := srv.Since.Truncate(time.Second)
|
copied := srv.Since.Truncate(time.Second)
|
||||||
status.Since = &copied
|
status.Since = &copied
|
||||||
|
@ -199,7 +197,7 @@ func getSubscribersHelper(srvMap *sync.Map) *SubscriberStatus {
|
||||||
func delSubscribers(w http.ResponseWriter, r *http.Request) {
|
func delSubscribers(w http.ResponseWriter, r *http.Request) {
|
||||||
subject := chi.URLParam(r, "subject")
|
subject := chi.URLParam(r, "subject")
|
||||||
|
|
||||||
ok := table.Remove(subject)
|
ok := Remove(subject)
|
||||||
if !ok {
|
if !ok {
|
||||||
// TODO should this be an error?
|
// TODO should this be an error?
|
||||||
_ = json.NewEncoder(w).Encode(&struct {
|
_ = json.NewEncoder(w).Encode(&struct {
|
||||||
|
@ -243,7 +241,7 @@ func upgradeWebsocket(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
wsTun := telebit.NewWebsocketTunnel(conn)
|
wsTun := NewWebsocketTunnel(conn)
|
||||||
fmt.Printf("New Authenticated WebSocket Remote Server\n")
|
fmt.Printf("New Authenticated WebSocket Remote Server\n")
|
||||||
fmt.Printf("\thttp.req.RemoteAddr: %+v\n", r.RemoteAddr)
|
fmt.Printf("\thttp.req.RemoteAddr: %+v\n", r.RemoteAddr)
|
||||||
fmt.Printf("\tconn.RemoteAddr(): %+v\n", conn.RemoteAddr())
|
fmt.Printf("\tconn.RemoteAddr(): %+v\n", conn.RemoteAddr())
|
||||||
|
@ -255,15 +253,15 @@ func upgradeWebsocket(w http.ResponseWriter, r *http.Request) {
|
||||||
// Rather the client's local address (the specific relay server) would be more useful.
|
// Rather the client's local address (the specific relay server) would be more useful.
|
||||||
ctxEncoder, cancelEncoder := context.WithCancel(context.Background())
|
ctxEncoder, cancelEncoder := context.WithCancel(context.Background())
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
server := &table.SubscriberConn{
|
server := &SubscriberConn{
|
||||||
Since: &now,
|
Since: &now,
|
||||||
RemoteAddr: r.RemoteAddr,
|
RemoteAddr: r.RemoteAddr,
|
||||||
WSConn: conn,
|
WSConn: conn,
|
||||||
WSTun: wsTun,
|
WSTun: wsTun,
|
||||||
Grants: grants,
|
Grants: grants,
|
||||||
Clients: &sync.Map{},
|
Clients: &sync.Map{},
|
||||||
MultiEncoder: telebit.NewEncoder(ctxEncoder, wsTun),
|
MultiEncoder: NewEncoder(ctxEncoder, wsTun),
|
||||||
MultiDecoder: telebit.NewDecoder(wsTun),
|
MultiDecoder: NewDecoder(wsTun),
|
||||||
}
|
}
|
||||||
// TODO should this happen at NewEncoder()?
|
// TODO should this happen at NewEncoder()?
|
||||||
// (or is it even necessary anymore?)
|
// (or is it even necessary anymore?)
|
||||||
|
@ -283,8 +281,8 @@ func upgradeWebsocket(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Printf("a subscriber stream is done: %q\n", err)
|
fmt.Printf("a subscriber stream is done: %q\n", err)
|
||||||
// TODO check what happens when we leave a junk connection
|
// TODO check what happens when we leave a junk connection
|
||||||
//fmt.Println("[debug] [warn] removing server turned off")
|
//fmt.Println("[debug] [warn] removing server turned off")
|
||||||
table.RemoveServer(server)
|
RemoveServer(server)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
table.Add(server)
|
Add(server)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,10 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.rootprojects.org/root/telebit"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewAuthorizer(authURL string) telebit.Authorizer {
|
func NewAuthorizer(authURL string) Authorizer {
|
||||||
return func(r *http.Request) (*telebit.Grants, error) {
|
return func(r *http.Request) (*Grants, error) {
|
||||||
// do we have a valid wss_client?
|
// do we have a valid wss_client?
|
||||||
|
|
||||||
fmt.Printf("[authz] Authorization = %s\n", r.Header.Get("Authorization"))
|
fmt.Printf("[authz] Authorization = %s\n", r.Header.Get("Authorization"))
|
||||||
|
@ -28,7 +26,7 @@ func NewAuthorizer(authURL string) telebit.Authorizer {
|
||||||
|
|
||||||
fmt.Printf("[authz] authURL = %s\n", authURL)
|
fmt.Printf("[authz] authURL = %s\n", authURL)
|
||||||
fmt.Printf("[authz] token = %s\n", tokenString)
|
fmt.Printf("[authz] token = %s\n", tokenString)
|
||||||
grants, err := telebit.Inspect(authURL, tokenString)
|
grants, err := Inspect(authURL, tokenString)
|
||||||
|
|
||||||
if nil != err {
|
if nil != err {
|
||||||
fmt.Printf("[authorizer] error inspecting %q: %s\ntoken: %s\n", authURL, err, tokenString)
|
fmt.Printf("[authorizer] error inspecting %q: %s\ntoken: %s\n", authURL, err, tokenString)
|
||||||
|
|
|
@ -7,8 +7,8 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.rootprojects.org/root/telebit/dbg"
|
"git.rootprojects.org/root/telebit/internal/dbg"
|
||||||
"git.rootprojects.org/root/telebit/sni"
|
"git.rootprojects.org/root/telebit/internal/sni"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ConnWrap is just a cheap way to DRY up some switch conn.(type) statements to handle special features of Conn
|
// ConnWrap is just a cheap way to DRY up some switch conn.(type) statements to handle special features of Conn
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.rootprojects.org/root/telebit/dbg"
|
"git.rootprojects.org/root/telebit/internal/dbg"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Decoder handles a Reader stream containing mplexy-encoded clients
|
// Decoder handles a Reader stream containing mplexy-encoded clients
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"git.rootprojects.org/root/telebit/dbg"
|
"git.rootprojects.org/root/telebit/internal/dbg"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: try to be more like encoding/csv, or more like encoding/pem and encoding/json?
|
// TODO: try to be more like encoding/csv, or more like encoding/pem and encoding/json?
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.rootprojects.org/root/telebit/dbg"
|
"git.rootprojects.org/root/telebit/internal/dbg"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Listener transforms a multiplexed websocket connection into individual net.Conn-like connections.
|
// A Listener transforms a multiplexed websocket connection into individual net.Conn-like connections.
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.rootprojects.org/root/telebit/dbg"
|
"git.rootprojects.org/root/telebit/internal/dbg"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Parser struct {
|
type Parser struct {
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.rootprojects.org/root/telebit/dbg"
|
"git.rootprojects.org/root/telebit/internal/dbg"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A RouteMux is a net.Conn multiplexer.
|
// A RouteMux is a net.Conn multiplexer.
|
|
@ -1,18 +1,17 @@
|
||||||
package table
|
package telebit
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"io"
|
"git.rootprojects.org/root/telebit/internal/dbg"
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
telebit "git.rootprojects.org/root/telebit"
|
|
||||||
"git.rootprojects.org/root/telebit/dbg"
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -108,18 +107,18 @@ type SubscriberConn struct {
|
||||||
Since *time.Time
|
Since *time.Time
|
||||||
RemoteAddr string
|
RemoteAddr string
|
||||||
WSConn *websocket.Conn
|
WSConn *websocket.Conn
|
||||||
WSTun net.Conn // *telebit.WebsocketTunnel
|
WSTun net.Conn // *WebsocketTunnel
|
||||||
Grants *telebit.Grants
|
Grants *Grants
|
||||||
Clients *sync.Map
|
Clients *sync.Map
|
||||||
|
|
||||||
// TODO is this the right codec type?
|
// TODO is this the right codec type?
|
||||||
MultiEncoder *telebit.Encoder
|
MultiEncoder *Encoder
|
||||||
MultiDecoder *telebit.Decoder
|
MultiDecoder *Decoder
|
||||||
|
|
||||||
// to fulfill Router interface
|
// to fulfill Router interface
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SubscriberConn) RouteBytes(src, dst telebit.Addr, payload []byte) {
|
func (s *SubscriberConn) RouteBytes(src, dst Addr, payload []byte) {
|
||||||
id := fmt.Sprintf("%s:%d", src.Hostname(), src.Port())
|
id := fmt.Sprintf("%s:%d", src.Hostname(), src.Port())
|
||||||
if dbg.Debug {
|
if dbg.Debug {
|
||||||
fmt.Fprintf(
|
fmt.Fprintf(
|
||||||
|
@ -163,9 +162,9 @@ func (s *SubscriberConn) RouteBytes(src, dst telebit.Addr, payload []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SubscriberConn) Serve(client net.Conn) error {
|
func (s *SubscriberConn) Serve(client net.Conn) error {
|
||||||
var wconn *telebit.ConnWrap
|
var wconn *ConnWrap
|
||||||
switch conn := client.(type) {
|
switch conn := client.(type) {
|
||||||
case *telebit.ConnWrap:
|
case *ConnWrap:
|
||||||
wconn = conn
|
wconn = conn
|
||||||
default:
|
default:
|
||||||
// this probably isn't strictly necessary
|
// this probably isn't strictly necessary
|
||||||
|
@ -201,27 +200,27 @@ func (s *SubscriberConn) Serve(client net.Conn) error {
|
||||||
|
|
||||||
servername := wconn.Servername()
|
servername := wconn.Servername()
|
||||||
|
|
||||||
termination := telebit.Unknown
|
termination := Unknown
|
||||||
scheme := telebit.None
|
scheme := None
|
||||||
if "" != servername {
|
if "" != servername {
|
||||||
dstAddr = servername
|
dstAddr = servername
|
||||||
//scheme = telebit.TLS
|
//scheme = TLS
|
||||||
scheme = telebit.HTTPS
|
scheme = HTTPS
|
||||||
}
|
}
|
||||||
if 80 == dstPort {
|
if 80 == dstPort {
|
||||||
scheme = telebit.HTTPS
|
scheme = HTTPS
|
||||||
} else if 443 == dstPort {
|
} else if 443 == dstPort {
|
||||||
// TODO dstAddr = wconn.Servername()
|
// TODO dstAddr = wconn.Servername()
|
||||||
scheme = telebit.HTTP
|
scheme = HTTP
|
||||||
}
|
}
|
||||||
|
|
||||||
src := telebit.NewAddr(
|
src := NewAddr(
|
||||||
scheme,
|
scheme,
|
||||||
termination,
|
termination,
|
||||||
srcAddr,
|
srcAddr,
|
||||||
srcPort,
|
srcPort,
|
||||||
)
|
)
|
||||||
dst := telebit.NewAddr(
|
dst := NewAddr(
|
||||||
scheme,
|
scheme,
|
||||||
termination,
|
termination,
|
||||||
dstAddr,
|
dstAddr,
|
|
@ -16,8 +16,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.rootprojects.org/root/telebit/dbg"
|
"git.rootprojects.org/root/telebit/internal/dbg"
|
||||||
httpshim "git.rootprojects.org/root/telebit/tunnel"
|
httpshim "git.rootprojects.org/root/telebit/internal/tunnel"
|
||||||
|
|
||||||
"github.com/coolaj86/certmagic"
|
"github.com/coolaj86/certmagic"
|
||||||
"github.com/mholt/acmez"
|
"github.com/mholt/acmez"
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.rootprojects.org/root/telebit/dbg"
|
"git.rootprojects.org/root/telebit/internal/dbg"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.rootprojects.org/root/telebit/dbg"
|
"git.rootprojects.org/root/telebit/internal/dbg"
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
|
@ -1,8 +0,0 @@
|
||||||
TOKEN=$(go run cmd/signjwt/*.go)
|
|
||||||
echo "TOKEN: $TOKEN"
|
|
||||||
|
|
||||||
echo "Active:"
|
|
||||||
curl -L http://localhost:3000/api/devices -H "Authorization: Bearer ${TOKEN}"
|
|
||||||
|
|
||||||
echo "Inactive:"
|
|
||||||
curl -L http://localhost:3000/api/devices?inactive=true -H "Authorization: Bearer ${TOKEN}"
|
|
43
mgmt.sh
43
mgmt.sh
|
@ -1,43 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
set -u
|
|
||||||
|
|
||||||
# 1. (srv) create a new shared key for a given slug
|
|
||||||
# 2. (dev) try to update via ping
|
|
||||||
# 3. (dev) use key to exchange machine id
|
|
||||||
# 4. (dev) use key to connect to remote
|
|
||||||
# 5. (dev) ping occasionally
|
|
||||||
|
|
||||||
TOKEN=$(go run cmd/signjwt/*.go)
|
|
||||||
echo "TOKEN: $TOKEN"
|
|
||||||
|
|
||||||
my_shared="ZR2rxYmcKJcmtKgmH9D5Qw"
|
|
||||||
my_domain="example.com"
|
|
||||||
my_client="1-client-slug"
|
|
||||||
TOK=$(curl -X POST http://localhost:3000/api/devices -H "Authorization: Bearer ${TOKEN}" -H "Content-Type: application/json" -d '{ "slug": "'$my_client'", "shared_key": "'$my_shared'" }')
|
|
||||||
echo Response: $TOK
|
|
||||||
|
|
||||||
SHARED=$(echo "$TOK" | sed 's/.*shared_key":"//g' | sed 's/".*//')
|
|
||||||
echo Shared Key: $SHARED
|
|
||||||
my_parts=$(go run cmd/signjwt/*.go $SHARED machineid)
|
|
||||||
my_ppid=$(echo $my_parts | cut -d' ' -f1)
|
|
||||||
my_keyid=$(echo $my_parts | cut -d' ' -f2)
|
|
||||||
echo "PPID: $my_ppid KeyID: $my_keyid"
|
|
||||||
|
|
||||||
TOKEN=$(go run cmd/signjwt/*.go $my_ppid)
|
|
||||||
echo "PING 1 (should fail)"
|
|
||||||
curl -X POST http://localhost:3000/api/ping -H "Authorization: Bearer ${TOKEN}"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
curl -X POST http://localhost:3000/api/register-device/$SHARED -H "Content-Type: application/json" -d '{ "machine_ppid": "'$my_ppid'", "public_key": "'$my_keyid'" }'
|
|
||||||
echo ''
|
|
||||||
|
|
||||||
echo "PING 2 (should work)"
|
|
||||||
curl -X POST http://localhost:3000/api/ping -H "Authorization: Bearer ${TOKEN}"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
curl -X POST http://localhost:3000/api/dns/"${my_client}.${my_domain}" \
|
|
||||||
-H "Authorization: Bearer ${TOKEN}" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{ "token": "xxxx", "key_authorization": "yyyy" }'
|
|
Loading…
Reference in New Issue