mirror of
https://github.com/openziti/zrok.git
synced 2025-02-16 18:20:51 +01:00
basic unique name implementation (#123)
This commit is contained in:
parent
ead350b442
commit
f61b2c9086
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/openziti/zrok/environment"
|
"github.com/openziti/zrok/environment"
|
||||||
"github.com/openziti/zrok/sdk/golang/sdk"
|
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||||
"github.com/openziti/zrok/tui"
|
"github.com/openziti/zrok/tui"
|
||||||
|
"github.com/openziti/zrok/util"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"slices"
|
"slices"
|
||||||
@ -17,6 +18,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type reserveCommand struct {
|
type reserveCommand struct {
|
||||||
|
uniqueName string
|
||||||
basicAuth []string
|
basicAuth []string
|
||||||
frontendSelection []string
|
frontendSelection []string
|
||||||
backendMode string
|
backendMode string
|
||||||
@ -34,6 +36,7 @@ func newReserveCommand() *reserveCommand {
|
|||||||
Args: cobra.ExactArgs(2),
|
Args: cobra.ExactArgs(2),
|
||||||
}
|
}
|
||||||
command := &reserveCommand{cmd: cmd}
|
command := &reserveCommand{cmd: cmd}
|
||||||
|
cmd.Flags().StringVarP(&command.uniqueName, "unique-name", "n", "", "A unique name for the reserved share (defaults to generated identifier)")
|
||||||
cmd.Flags().StringArrayVar(&command.frontendSelection, "frontends", []string{"public"}, "Selected frontends to use for the share")
|
cmd.Flags().StringArrayVar(&command.frontendSelection, "frontends", []string{"public"}, "Selected frontends to use for the share")
|
||||||
cmd.Flags().StringVarP(&command.backendMode, "backend-mode", "b", "proxy", "The backend mode (public|private: proxy, web, caddy, drive) (private: tcpTunnel, udpTunnel)")
|
cmd.Flags().StringVarP(&command.backendMode, "backend-mode", "b", "proxy", "The backend mode (public|private: proxy, web, caddy, drive) (private: tcpTunnel, udpTunnel)")
|
||||||
cmd.Flags().BoolVarP(&command.jsonOutput, "json-output", "j", false, "Emit JSON describing the created reserved share")
|
cmd.Flags().BoolVarP(&command.jsonOutput, "json-output", "j", false, "Emit JSON describing the created reserved share")
|
||||||
@ -56,6 +59,10 @@ func (cmd *reserveCommand) run(_ *cobra.Command, args []string) {
|
|||||||
tui.Error(fmt.Sprintf("invalid sharing mode for a %s share: %s", sdk.PublicShareMode, cmd.backendMode), nil)
|
tui.Error(fmt.Sprintf("invalid sharing mode for a %s share: %s", sdk.PublicShareMode, cmd.backendMode), nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cmd.uniqueName != "" && !util.IsValidUniqueName(cmd.uniqueName) {
|
||||||
|
tui.Error("invalid unique name; must be lowercase alphanumeric, between 4 and 32 characters in length, screened for profanity", nil)
|
||||||
|
}
|
||||||
|
|
||||||
var target string
|
var target string
|
||||||
switch cmd.backendMode {
|
switch cmd.backendMode {
|
||||||
case "proxy":
|
case "proxy":
|
||||||
@ -95,6 +102,7 @@ func (cmd *reserveCommand) run(_ *cobra.Command, args []string) {
|
|||||||
|
|
||||||
req := &sdk.ShareRequest{
|
req := &sdk.ShareRequest{
|
||||||
Reserved: true,
|
Reserved: true,
|
||||||
|
UniqueName: cmd.uniqueName,
|
||||||
BackendMode: sdk.BackendMode(cmd.backendMode),
|
BackendMode: sdk.BackendMode(cmd.backendMode),
|
||||||
ShareMode: shareMode,
|
ShareMode: shareMode,
|
||||||
BasicAuth: cmd.basicAuth,
|
BasicAuth: cmd.basicAuth,
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"github.com/openziti/zrok/rest_model_zrok"
|
"github.com/openziti/zrok/rest_model_zrok"
|
||||||
"github.com/openziti/zrok/rest_server_zrok/operations/share"
|
"github.com/openziti/zrok/rest_server_zrok/operations/share"
|
||||||
"github.com/openziti/zrok/sdk/golang/sdk"
|
"github.com/openziti/zrok/sdk/golang/sdk"
|
||||||
|
"github.com/openziti/zrok/util"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
@ -33,14 +34,14 @@ func (h *shareHandler) Handle(params share.ShareParams, principal *rest_model_zr
|
|||||||
found := false
|
found := false
|
||||||
for _, env := range envs {
|
for _, env := range envs {
|
||||||
if env.ZId == envZId {
|
if env.ZId == envZId {
|
||||||
logrus.Debugf("found identity '%v' for user '%v'", envZId, principal.Email)
|
logrus.Debugf("found identity '%v' for account '%v'", envZId, principal.Email)
|
||||||
envId = env.Id
|
envId = env.Id
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
logrus.Errorf("environment '%v' not found for user '%v'", envZId, principal.Email)
|
logrus.Errorf("environment '%v' not found for account '%v'", envZId, principal.Email)
|
||||||
return share.NewShareUnauthorized()
|
return share.NewShareUnauthorized()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -58,11 +59,21 @@ func (h *shareHandler) Handle(params share.ShareParams, principal *rest_model_zr
|
|||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
return share.NewShareInternalServerError()
|
return share.NewShareInternalServerError()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reserved := params.Body.Reserved
|
||||||
|
uniqueName := params.Body.UniqueName
|
||||||
shrToken, err := createShareToken()
|
shrToken, err := createShareToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
return share.NewShareInternalServerError()
|
return share.NewShareInternalServerError()
|
||||||
}
|
}
|
||||||
|
if reserved && uniqueName != "" {
|
||||||
|
if !util.IsValidUniqueName(uniqueName) {
|
||||||
|
logrus.Errorf("invalid unique name '%v' for account '%v'", uniqueName, principal.Email)
|
||||||
|
return share.NewShareUnprocessableEntity()
|
||||||
|
}
|
||||||
|
shrToken = uniqueName
|
||||||
|
}
|
||||||
|
|
||||||
var shrZId string
|
var shrZId string
|
||||||
var frontendEndpoints []string
|
var frontendEndpoints []string
|
||||||
@ -94,7 +105,6 @@ func (h *shareHandler) Handle(params share.ShareParams, principal *rest_model_zr
|
|||||||
}
|
}
|
||||||
|
|
||||||
case string(sdk.PrivateShareMode):
|
case string(sdk.PrivateShareMode):
|
||||||
logrus.Info("doing private")
|
|
||||||
shrZId, frontendEndpoints, err = newPrivateResourceAllocator().allocate(envZId, shrToken, params, edge)
|
shrZId, frontendEndpoints, err = newPrivateResourceAllocator().allocate(envZId, shrToken, params, edge)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
@ -108,7 +118,6 @@ func (h *shareHandler) Handle(params share.ShareParams, principal *rest_model_zr
|
|||||||
|
|
||||||
logrus.Debugf("allocated share '%v'", shrToken)
|
logrus.Debugf("allocated share '%v'", shrToken)
|
||||||
|
|
||||||
reserved := params.Body.Reserved
|
|
||||||
sshr := &store.Share{
|
sshr := &store.Share{
|
||||||
ZId: shrZId,
|
ZId: shrZId,
|
||||||
Token: shrToken,
|
Token: shrToken,
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
-- +migrate Up
|
||||||
|
|
||||||
|
-- remove the old unique index (which did not respect the deleted flag)
|
||||||
|
ALTER TABLE shares DROP CONSTRAINT shares_token_key;
|
||||||
|
|
||||||
|
-- add a new unique index which only constrains uniqueness for not-deleted rows
|
||||||
|
CREATE UNIQUE INDEX shares_token_idx ON shares(token) WHERE deleted is false;
|
3
go.mod
3
go.mod
@ -3,6 +3,7 @@ module github.com/openziti/zrok
|
|||||||
go 1.20
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/TwiN/go-away v1.6.12
|
||||||
github.com/caddyserver/caddy/v2 v2.7.5-0.20230829153420-ed8bb13c5df7
|
github.com/caddyserver/caddy/v2 v2.7.5-0.20230829153420-ed8bb13c5df7
|
||||||
github.com/charmbracelet/bubbles v0.14.0
|
github.com/charmbracelet/bubbles v0.14.0
|
||||||
github.com/charmbracelet/bubbletea v0.23.1
|
github.com/charmbracelet/bubbletea v0.23.1
|
||||||
@ -226,7 +227,7 @@ require (
|
|||||||
golang.org/x/sync v0.3.0 // indirect
|
golang.org/x/sync v0.3.0 // indirect
|
||||||
golang.org/x/sys v0.11.0 // indirect
|
golang.org/x/sys v0.11.0 // indirect
|
||||||
golang.org/x/term v0.11.0 // indirect
|
golang.org/x/term v0.11.0 // indirect
|
||||||
golang.org/x/text v0.12.0 // indirect
|
golang.org/x/text v0.14.0 // indirect
|
||||||
golang.org/x/tools v0.10.0 // indirect
|
golang.org/x/tools v0.10.0 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 // indirect
|
google.golang.org/genproto v0.0.0-20230706204954-ccb25ca9f130 // indirect
|
||||||
|
6
go.sum
6
go.sum
@ -114,6 +114,8 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt
|
|||||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
|
||||||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
|
||||||
|
github.com/TwiN/go-away v1.6.12 h1:80AjDyeTjfQaSFYbALzRcDKMAmxKW0a5PoxwXKZlW2A=
|
||||||
|
github.com/TwiN/go-away v1.6.12/go.mod h1:MpvIC9Li3minq+CGgbgUDvQ9tDaeW35k5IXZrF9MVas=
|
||||||
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
|
||||||
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
|
||||||
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
|
||||||
@ -1792,8 +1794,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
|||||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
@ -22,6 +22,7 @@ const (
|
|||||||
|
|
||||||
type ShareRequest struct {
|
type ShareRequest struct {
|
||||||
Reserved bool
|
Reserved bool
|
||||||
|
UniqueName string
|
||||||
BackendMode BackendMode
|
BackendMode BackendMode
|
||||||
ShareMode ShareMode
|
ShareMode ShareMode
|
||||||
Target string
|
Target string
|
||||||
|
@ -26,6 +26,9 @@ func CreateShare(root env_core.Root, request *ShareRequest) (*Share, error) {
|
|||||||
return nil, errors.Errorf("unknown share mode '%v'", request.ShareMode)
|
return nil, errors.Errorf("unknown share mode '%v'", request.ShareMode)
|
||||||
}
|
}
|
||||||
out.Body.Reserved = request.Reserved
|
out.Body.Reserved = request.Reserved
|
||||||
|
if request.Reserved {
|
||||||
|
out.Body.UniqueName = request.UniqueName
|
||||||
|
}
|
||||||
|
|
||||||
if len(request.BasicAuth) > 0 {
|
if len(request.BasicAuth) > 0 {
|
||||||
out.Body.AuthScheme = string(Basic)
|
out.Body.AuthScheme = string(Basic)
|
||||||
|
@ -27,6 +27,8 @@ def CreateShare(root: Root, request: model.ShareRequest) -> model.Share:
|
|||||||
if request.OauthProvider != "":
|
if request.OauthProvider != "":
|
||||||
out.auth_scheme = model.AUTH_SCHEME_OAUTH
|
out.auth_scheme = model.AUTH_SCHEME_OAUTH
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
zrok = root.Client()
|
zrok = root.Client()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
18
util/uniqueName.go
Normal file
18
util/uniqueName.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
goaway "github.com/TwiN/go-away"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsValidUniqueName ensures that the string represents a valid unique name. Lowercase alphanumeric only. 4-32 characters.
|
||||||
|
func IsValidUniqueName(uniqueName string) bool {
|
||||||
|
match, err := regexp.Match("^[a-z0-9]{4,32}$", []byte(uniqueName))
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if match && goaway.IsProfane(uniqueName) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return match
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user