mirror of https://github.com/cbeuw/Cloak
Allow DatabasePath to be empty if user info database is never used
This commit is contained in:
parent
298e6249e6
commit
0d3f8dd27f
14
README.md
14
README.md
|
|
@ -103,15 +103,13 @@ Example:
|
||||||
|
|
||||||
`PrivateKey` is the static curve25519 Diffie-Hellman private key encoded in base64.
|
`PrivateKey` is the static curve25519 Diffie-Hellman private key encoded in base64.
|
||||||
|
|
||||||
`AdminUID` is the UID of the admin user in base64.
|
|
||||||
|
|
||||||
`BypassUID` is a list of UIDs that are authorised without any bandwidth or credit limit restrictions
|
`BypassUID` is a list of UIDs that are authorised without any bandwidth or credit limit restrictions
|
||||||
|
|
||||||
`DatabasePath` is the path to `userinfo.db`. If `userinfo.db` doesn't exist in this directory, Cloak will create one
|
`AdminUID` is the UID of the admin user in base64. You can leave this empty if you only ever add users to `BypassUID`.
|
||||||
automatically. **If Cloak is started as a Shadowsocks plugin and Shadowsocks is started with its working directory as
|
|
||||||
/ (e.g. starting ss-server with systemctl), you need to set this field as an absolute path to a desired folder. If you
|
`DatabasePath` is the path to `userinfo.db`, which is used to store user usage information and restrictions. Cloak will
|
||||||
leave it as default then Cloak will attempt to create userinfo.db under /, which it doesn't have the permission to do so
|
create the file automatically if it doesn't exist. You can leave this empty if you only ever add users to `BypassUID`.
|
||||||
and will raise an error. See Issue #13.**
|
This field also has no effect if `AdminUID` isn't a valid UID or is empty.
|
||||||
|
|
||||||
`KeepAlive` is the number of seconds to tell the OS to wait after no activity before sending TCP KeepAlive probes to the
|
`KeepAlive` is the number of seconds to tell the OS to wait after no activity before sending TCP KeepAlive probes to the
|
||||||
upstream proxy server. Zero or negative value disables it. Default is 0 (disabled).
|
upstream proxy server. Zero or negative value disables it. Default is 0 (disabled).
|
||||||
|
|
@ -184,6 +182,8 @@ Run `ck-server -uid` and add the UID into the `BypassUID` field in `ckserver.jso
|
||||||
|
|
||||||
##### Users subject to bandwidth and credit controls
|
##### Users subject to bandwidth and credit controls
|
||||||
|
|
||||||
|
0. First make sure you have `AdminUID` generated and set in `ckserver.json`, along with a path to `userinfo.db`
|
||||||
|
in `DatabasePath` (Cloak will create this file for you if it didn't already exist).
|
||||||
1. On your client, run `ck-client -s <IP of the server> -l <A local port> -a <AdminUID> -c <path-to-ckclient.json>` to
|
1. On your client, run `ck-client -s <IP of the server> -l <A local port> -a <AdminUID> -c <path-to-ckclient.json>` to
|
||||||
enter admin mode
|
enter admin mode
|
||||||
2. Visit https://cbeuw.github.io/Cloak-panel (Note: this is a pure-js static site, there is no backend and all data
|
2. Visit https://cbeuw.github.io/Cloak-panel (Note: this is a pure-js static site, there is no backend and all data
|
||||||
|
|
|
||||||
|
|
@ -143,10 +143,15 @@ func InitState(preParse RawConfig, worldState common.WorldState) (sta *State, er
|
||||||
err = errors.New("command & control mode not implemented")
|
err = errors.New("command & control mode not implemented")
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
manager, err := usermanager.MakeLocalManager(preParse.DatabasePath, worldState)
|
var manager usermanager.UserManager
|
||||||
|
if len(preParse.AdminUID) == 0 || preParse.DatabasePath == "" {
|
||||||
|
manager = &usermanager.Voidmanager{}
|
||||||
|
} else {
|
||||||
|
manager, err = usermanager.MakeLocalManager(preParse.DatabasePath, worldState)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sta, err
|
return sta, err
|
||||||
}
|
}
|
||||||
|
}
|
||||||
sta.Panel = MakeUserPanel(manager)
|
sta.Panel = MakeUserPanel(manager)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ const (
|
||||||
|
|
||||||
var ErrUserNotFound = errors.New("UID does not correspond to a user")
|
var ErrUserNotFound = errors.New("UID does not correspond to a user")
|
||||||
var ErrSessionsCapReached = errors.New("Sessions cap has reached")
|
var ErrSessionsCapReached = errors.New("Sessions cap has reached")
|
||||||
|
var ErrMangerIsVoid = errors.New("cannot perform operation with user manager as database path is not specified")
|
||||||
|
|
||||||
var ErrNoUpCredit = errors.New("No upload credit left")
|
var ErrNoUpCredit = errors.New("No upload credit left")
|
||||||
var ErrNoDownCredit = errors.New("No download credit left")
|
var ErrNoDownCredit = errors.New("No download credit left")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
package usermanager
|
||||||
|
|
||||||
|
type Voidmanager struct{}
|
||||||
|
|
||||||
|
func (v *Voidmanager) AuthenticateUser(bytes []byte) (int64, int64, error) {
|
||||||
|
return 0, 0, ErrMangerIsVoid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Voidmanager) AuthoriseNewSession(bytes []byte, info AuthorisationInfo) error {
|
||||||
|
return ErrMangerIsVoid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Voidmanager) UploadStatus(updates []StatusUpdate) ([]StatusResponse, error) {
|
||||||
|
return nil, ErrMangerIsVoid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Voidmanager) ListAllUsers() ([]UserInfo, error) {
|
||||||
|
return nil, ErrMangerIsVoid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Voidmanager) GetUserInfo(UID []byte) (UserInfo, error) {
|
||||||
|
return UserInfo{}, ErrMangerIsVoid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Voidmanager) WriteUserInfo(info UserInfo) error {
|
||||||
|
return ErrMangerIsVoid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Voidmanager) DeleteUser(UID []byte) error {
|
||||||
|
return ErrMangerIsVoid
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package usermanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var v = &Voidmanager{}
|
||||||
|
|
||||||
|
func Test_Voidmanager_AuthenticateUser(t *testing.T) {
|
||||||
|
_, _, err := v.AuthenticateUser([]byte{})
|
||||||
|
assert.Equal(t, ErrMangerIsVoid, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Voidmanager_AuthoriseNewSession(t *testing.T) {
|
||||||
|
err := v.AuthoriseNewSession([]byte{}, AuthorisationInfo{})
|
||||||
|
assert.Equal(t, ErrMangerIsVoid, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Voidmanager_DeleteUser(t *testing.T) {
|
||||||
|
err := v.DeleteUser([]byte{})
|
||||||
|
assert.Equal(t, ErrMangerIsVoid, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Voidmanager_GetUserInfo(t *testing.T) {
|
||||||
|
_, err := v.GetUserInfo([]byte{})
|
||||||
|
assert.Equal(t, ErrMangerIsVoid, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Voidmanager_ListAllUsers(t *testing.T) {
|
||||||
|
_, err := v.ListAllUsers()
|
||||||
|
assert.Equal(t, ErrMangerIsVoid, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Voidmanager_UploadStatus(t *testing.T) {
|
||||||
|
_, err := v.UploadStatus([]StatusUpdate{})
|
||||||
|
assert.Equal(t, ErrMangerIsVoid, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Voidmanager_WriteUserInfo(t *testing.T) {
|
||||||
|
err := v.WriteUserInfo(UserInfo{})
|
||||||
|
assert.Equal(t, ErrMangerIsVoid, err)
|
||||||
|
}
|
||||||
|
|
@ -185,6 +185,9 @@ func (panel *userPanel) commitUpdate() error {
|
||||||
panel.usageUpdateQueue = make(map[[16]byte]*usagePair)
|
panel.usageUpdateQueue = make(map[[16]byte]*usagePair)
|
||||||
panel.usageUpdateQueueM.Unlock()
|
panel.usageUpdateQueueM.Unlock()
|
||||||
|
|
||||||
|
if len(statuses) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
responses, err := panel.Manager.UploadStatus(statuses)
|
responses, err := panel.Manager.UploadStatus(statuses)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,8 @@ import (
|
||||||
"github.com/cbeuw/connutil"
|
"github.com/cbeuw/connutil"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -24,8 +22,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const numConns = 200 // -race option limits the number of goroutines to 8192
|
const numConns = 200 // -race option limits the number of goroutines to 8192
|
||||||
const delayBeforeTestingConnClose = 500 * time.Millisecond
|
|
||||||
const connCloseRetries = 3
|
|
||||||
|
|
||||||
func serveTCPEcho(l net.Listener) {
|
func serveTCPEcho(l net.Listener) {
|
||||||
for {
|
for {
|
||||||
|
|
@ -137,15 +133,13 @@ func generateClientConfigs(rawConfig client.RawConfig, state common.WorldState)
|
||||||
return lcl, rmt, auth
|
return lcl, rmt, auth
|
||||||
}
|
}
|
||||||
|
|
||||||
func basicServerState(ws common.WorldState, db *os.File) *server.State {
|
func basicServerState(ws common.WorldState) *server.State {
|
||||||
var serverConfig = server.RawConfig{
|
var serverConfig = server.RawConfig{
|
||||||
ProxyBook: map[string][]string{"shadowsocks": {"tcp", "fake.com:9999"}, "openvpn": {"udp", "fake.com:9999"}},
|
ProxyBook: map[string][]string{"shadowsocks": {"tcp", "fake.com:9999"}, "openvpn": {"udp", "fake.com:9999"}},
|
||||||
BindAddr: []string{"fake.com:9999"},
|
BindAddr: []string{"fake.com:9999"},
|
||||||
BypassUID: [][]byte{bypassUID[:]},
|
BypassUID: [][]byte{bypassUID[:]},
|
||||||
RedirAddr: "fake.com:9999",
|
RedirAddr: "fake.com:9999",
|
||||||
PrivateKey: privateKey,
|
PrivateKey: privateKey,
|
||||||
AdminUID: nil,
|
|
||||||
DatabasePath: db.Name(),
|
|
||||||
KeepAlive: 15,
|
KeepAlive: 15,
|
||||||
CncMode: false,
|
CncMode: false,
|
||||||
}
|
}
|
||||||
|
|
@ -258,13 +252,11 @@ func runEchoTest(t *testing.T, conns []net.Conn, maxMsgLen int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUDP(t *testing.T) {
|
func TestUDP(t *testing.T) {
|
||||||
var tmpDB, _ = ioutil.TempFile("", "ck_user_info")
|
|
||||||
defer os.Remove(tmpDB.Name())
|
|
||||||
log.SetLevel(log.ErrorLevel)
|
log.SetLevel(log.ErrorLevel)
|
||||||
|
|
||||||
worldState := common.WorldOfTime(time.Unix(10, 0))
|
worldState := common.WorldOfTime(time.Unix(10, 0))
|
||||||
lcc, rcc, ai := generateClientConfigs(basicUDPConfig, worldState)
|
lcc, rcc, ai := generateClientConfigs(basicUDPConfig, worldState)
|
||||||
sta := basicServerState(worldState, tmpDB)
|
sta := basicServerState(worldState)
|
||||||
|
|
||||||
proxyToCkClientD, proxyFromCkServerL, _, _, err := establishSession(lcc, rcc, ai, sta)
|
proxyToCkClientD, proxyFromCkServerL, _, _, err := establishSession(lcc, rcc, ai, sta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -319,9 +311,7 @@ func TestTCPSingleplex(t *testing.T) {
|
||||||
log.SetLevel(log.ErrorLevel)
|
log.SetLevel(log.ErrorLevel)
|
||||||
worldState := common.WorldOfTime(time.Unix(10, 0))
|
worldState := common.WorldOfTime(time.Unix(10, 0))
|
||||||
lcc, rcc, ai := generateClientConfigs(singleplexTCPConfig, worldState)
|
lcc, rcc, ai := generateClientConfigs(singleplexTCPConfig, worldState)
|
||||||
var tmpDB, _ = ioutil.TempFile("", "ck_user_info")
|
sta := basicServerState(worldState)
|
||||||
defer os.Remove(tmpDB.Name())
|
|
||||||
sta := basicServerState(worldState, tmpDB)
|
|
||||||
proxyToCkClientD, proxyFromCkServerL, _, _, err := establishSession(lcc, rcc, ai, sta)
|
proxyToCkClientD, proxyFromCkServerL, _, _, err := establishSession(lcc, rcc, ai, sta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|
@ -381,9 +371,7 @@ func TestTCPMultiplex(t *testing.T) {
|
||||||
worldState := common.WorldOfTime(time.Unix(10, 0))
|
worldState := common.WorldOfTime(time.Unix(10, 0))
|
||||||
|
|
||||||
lcc, rcc, ai := generateClientConfigs(basicTCPConfig, worldState)
|
lcc, rcc, ai := generateClientConfigs(basicTCPConfig, worldState)
|
||||||
var tmpDB, _ = ioutil.TempFile("", "ck_user_info")
|
sta := basicServerState(worldState)
|
||||||
defer os.Remove(tmpDB.Name())
|
|
||||||
sta := basicServerState(worldState, tmpDB)
|
|
||||||
|
|
||||||
proxyToCkClientD, proxyFromCkServerL, netToCkServerD, redirFromCkServerL, err := establishSession(lcc, rcc, ai, sta)
|
proxyToCkClientD, proxyFromCkServerL, netToCkServerD, redirFromCkServerL, err := establishSession(lcc, rcc, ai, sta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -456,11 +444,8 @@ func TestClosingStreamsFromProxy(t *testing.T) {
|
||||||
clientConfig := clientConfig
|
clientConfig := clientConfig
|
||||||
clientConfigName := clientConfigName
|
clientConfigName := clientConfigName
|
||||||
t.Run(clientConfigName, func(t *testing.T) {
|
t.Run(clientConfigName, func(t *testing.T) {
|
||||||
var tmpDB, _ = ioutil.TempFile("", "ck_user_info")
|
|
||||||
defer os.Remove(tmpDB.Name())
|
|
||||||
|
|
||||||
lcc, rcc, ai := generateClientConfigs(clientConfig, worldState)
|
lcc, rcc, ai := generateClientConfigs(clientConfig, worldState)
|
||||||
sta := basicServerState(worldState, tmpDB)
|
sta := basicServerState(worldState)
|
||||||
proxyToCkClientD, proxyFromCkServerL, _, _, err := establishSession(lcc, rcc, ai, sta)
|
proxyToCkClientD, proxyFromCkServerL, _, _, err := establishSession(lcc, rcc, ai, sta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|
@ -519,12 +504,10 @@ func TestClosingStreamsFromProxy(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkThroughput(b *testing.B) {
|
func BenchmarkThroughput(b *testing.B) {
|
||||||
var tmpDB, _ = ioutil.TempFile("", "ck_user_info")
|
|
||||||
defer os.Remove(tmpDB.Name())
|
|
||||||
log.SetLevel(log.ErrorLevel)
|
log.SetLevel(log.ErrorLevel)
|
||||||
worldState := common.WorldOfTime(time.Unix(10, 0))
|
worldState := common.WorldOfTime(time.Unix(10, 0))
|
||||||
lcc, rcc, ai := generateClientConfigs(basicTCPConfig, worldState)
|
lcc, rcc, ai := generateClientConfigs(basicTCPConfig, worldState)
|
||||||
sta := basicServerState(worldState, tmpDB)
|
sta := basicServerState(worldState)
|
||||||
const bufSize = 16 * 1024
|
const bufSize = 16 * 1024
|
||||||
|
|
||||||
encryptionMethods := map[string]byte{
|
encryptionMethods := map[string]byte{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue