mirror of
				https://codeberg.org/cunicu/cunicu.git
				synced 2025-10-31 07:56:23 +08:00 
			
		
		
		
	| @@ -10,7 +10,7 @@ import ( | ||||
| 	"go.uber.org/zap/zapio" | ||||
|  | ||||
| 	"github.com/stv0g/cunicu/pkg/config" | ||||
| 	d "github.com/stv0g/cunicu/pkg/daemon" | ||||
| 	"github.com/stv0g/cunicu/pkg/daemon" | ||||
| 	"github.com/stv0g/cunicu/pkg/rpc" | ||||
| 	"github.com/stv0g/cunicu/pkg/util/terminal" | ||||
| ) | ||||
| @@ -19,8 +19,8 @@ var ( | ||||
| 	daemonCmd = &cobra.Command{ | ||||
| 		Use:               "daemon [interface-names...]", | ||||
| 		Short:             "Start the daemon", | ||||
| 		Example:           `$ cunicu daemon -u -x mysecretpass wg0`, | ||||
| 		Run:               daemon, | ||||
| 		Example:           `$ cunicu daemon -U -x mysecretpass wg0`, | ||||
| 		Run:               daemonRun, | ||||
| 		ValidArgsFunction: cobra.NoFileCompletions, | ||||
| 	} | ||||
|  | ||||
| @@ -43,20 +43,22 @@ func init() { | ||||
| 		panic(err) | ||||
| 	} | ||||
|  | ||||
| 	if err := daemonCmd.MarkFlagFilename("config", "yaml", "json"); err != nil { | ||||
| 	if err := daemonCmd.MarkPersistentFlagFilename("config", "yaml", "json"); err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
|  | ||||
| 	pf.VisitAll(func(f *pflag.Flag) { | ||||
| 		if f.Value.Type() == "bool" { | ||||
| 			daemonCmd.RegisterFlagCompletionFunc(f.Name, BooleanCompletions) | ||||
| 			if err := daemonCmd.RegisterFlagCompletionFunc(f.Name, BooleanCompletions); err != nil { | ||||
| 				panic(err) | ||||
| 			} | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	rootCmd.AddCommand(daemonCmd) | ||||
| } | ||||
|  | ||||
| func daemon(cmd *cobra.Command, args []string) { | ||||
| func daemonRun(cmd *cobra.Command, args []string) { | ||||
| 	io.WriteString(os.Stdout, Banner(color)) | ||||
|  | ||||
| 	if err := cfg.Init(args); err != nil { | ||||
| @@ -76,7 +78,7 @@ func daemon(cmd *cobra.Command, args []string) { | ||||
| 	} | ||||
|  | ||||
| 	// Create daemon | ||||
| 	d, err := d.New(cfg) | ||||
| 	d, err := daemon.New(cfg) | ||||
| 	if err != nil { | ||||
| 		logger.Fatal("Failed to create daemon", zap.Error(err)) | ||||
| 	} | ||||
|   | ||||
| @@ -39,7 +39,10 @@ func init() { | ||||
|  | ||||
| func interfaceValidArg(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { | ||||
| 	// Establish RPC connection | ||||
| 	rpcConnect(cmd, args) | ||||
| 	if err := rpcConnect(cmd, args); err != nil { | ||||
| 		return nil, cobra.ShellCompDirectiveError | ||||
| 	} | ||||
|  | ||||
| 	defer rpcDisconnect(cmd, args) | ||||
|  | ||||
| 	p := &rpcproto.GetStatusParams{} | ||||
| @@ -100,11 +103,15 @@ func invite(cmd *cobra.Command, args []string) { | ||||
|  | ||||
| 		if qrCode { | ||||
| 			buf := &bytes.Buffer{} | ||||
| 			cfg.Dump(buf) | ||||
| 			if err := cfg.Dump(buf); err != nil { | ||||
| 				logger.Fatal("Failed to dump config", zap.Error(err)) | ||||
| 			} | ||||
|  | ||||
| 			terminal.QRCode(buf.String()) | ||||
| 		} else { | ||||
| 			cfg.Dump(os.Stdout) | ||||
| 			if err := cfg.Dump(os.Stdout); err != nil { | ||||
| 				logger.Fatal("Failed to dump config", zap.Error(err)) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -30,7 +30,7 @@ func init() { | ||||
| 	pf.VarP(&format, "format", "f", "Output `format` (one of: human, json)") | ||||
| 	pf.BoolVarP(&indent, "indent", "i", true, "Format and indent JSON ouput") | ||||
|  | ||||
| 	if err := daemonCmd.RegisterFlagCompletionFunc("format", cobra.FixedCompletions([]string{"human", "json"}, cobra.ShellCompDirectiveNoFileComp)); err != nil { | ||||
| 	if err := statusCmd.RegisterFlagCompletionFunc("format", cobra.FixedCompletions([]string{"human", "json"}, cobra.ShellCompDirectiveNoFileComp)); err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
|  | ||||
| @@ -39,7 +39,9 @@ func init() { | ||||
|  | ||||
| func statusValidArgs(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { | ||||
| 	// Establish RPC connection | ||||
| 	rpcConnect(cmd, args) | ||||
| 	if err := rpcConnect(cmd, args); err != nil { | ||||
| 		return nil, cobra.ShellCompDirectiveError | ||||
| 	} | ||||
| 	defer rpcDisconnect(cmd, args) | ||||
|  | ||||
| 	p := &rpcproto.GetStatusParams{} | ||||
|   | ||||
| @@ -48,7 +48,9 @@ func wgShowValidArgs(cmd *cobra.Command, args []string, toComplete string) ([]st | ||||
| 	if len(args) == 0 { | ||||
| 		comps = []string{"all", "interfaces"} | ||||
|  | ||||
| 		rpcConnect(cmd, args) | ||||
| 		if err := rpcConnect(cmd, args); err != nil { | ||||
| 			return nil, cobra.ShellCompDirectiveError | ||||
| 		} | ||||
| 		defer rpcDisconnect(cmd, args) | ||||
|  | ||||
| 		sts, err := rpcClient.GetStatus(context.Background(), &rpcproto.GetStatusParams{}) | ||||
|   | ||||
| @@ -108,4 +108,3 @@ sidebar_position: 20 | ||||
| [rfc7064]: https://datatracker.ietf.org/doc/html/rfc7064 | ||||
|  | ||||
| [rfc7065]: https://datatracker.ietf.org/doc/html/rfc7065 | ||||
|  | ||||
|   | ||||
| @@ -60,7 +60,7 @@ Please feel free to [join our Slack channel](https://join.slack.com/t/gophers/sh | ||||
|  | ||||
| ## Name | ||||
|  | ||||
| The project name _cunīcu_ [kʊˈniːkʊ] is derived from the [latin noun cunīculus](https://en.wiktionary.org/wiki/cuniculus#Latin) which means rabbit, a rabbit burrow or underground tunnel. We have choosen it as a name for this project as _cunīcu_ builds tunnels between otherwise hard to reach network locations. | ||||
| The project name _cunīcu_ \[kʊˈniːkʊ\] is derived from the [latin noun cunīculus](https://en.wiktionary.org/wiki/cuniculus#Latin) which means rabbit, a rabbit burrow or underground tunnel. We have choosen it as a name for this project as _cunīcu_ builds tunnels between otherwise hard to reach network locations. | ||||
| It has been changed from the former name _wice_ in order to broaden the scope of the project and avoid any potential trademark violations.  | ||||
|  | ||||
| ## License | ||||
|   | ||||
| @@ -13,24 +13,24 @@ import ( | ||||
| 	"github.com/stv0g/cunicu/pkg/util/buildinfo" | ||||
| ) | ||||
|  | ||||
| type remoteFileProvider struct { | ||||
| type RemoteFileProvider struct { | ||||
| 	url          *url.URL | ||||
| 	etag         string | ||||
| 	lastModified time.Time | ||||
| 	order        []string | ||||
| } | ||||
|  | ||||
| func RemoteFileProvider(u *url.URL) *remoteFileProvider { | ||||
| 	return &remoteFileProvider{ | ||||
| func NewRemoteFileProvider(u *url.URL) *RemoteFileProvider { | ||||
| 	return &RemoteFileProvider{ | ||||
| 		url: u, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (p *remoteFileProvider) Read() (map[string]interface{}, error) { | ||||
| func (p *RemoteFileProvider) Read() (map[string]interface{}, error) { | ||||
| 	return nil, errors.New("this provider does not support parsers") | ||||
| } | ||||
|  | ||||
| func (p *remoteFileProvider) ReadBytes() ([]byte, error) { | ||||
| func (p *RemoteFileProvider) ReadBytes() ([]byte, error) { | ||||
| 	if p.url.Scheme != "https" { | ||||
| 		host, _, err := net.SplitHostPort(p.url.Host) | ||||
| 		if err != nil { | ||||
| @@ -81,12 +81,14 @@ func (p *remoteFileProvider) ReadBytes() ([]byte, error) { | ||||
| 	return buf, nil | ||||
| } | ||||
|  | ||||
| func (p *remoteFileProvider) Order() []string { | ||||
| func (p *RemoteFileProvider) Order() []string { | ||||
| 	return p.order | ||||
| } | ||||
|  | ||||
| func (p *remoteFileProvider) Version() any { | ||||
| 	p.hasChanged() | ||||
| func (p *RemoteFileProvider) Version() any { | ||||
| 	if _, err := p.hasChanged(); err != nil { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	if p.etag != "" { | ||||
| 		return p.etag | ||||
| @@ -99,7 +101,7 @@ func (p *remoteFileProvider) Version() any { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (p *remoteFileProvider) hasChanged() (bool, error) { | ||||
| func (p *RemoteFileProvider) hasChanged() (bool, error) { | ||||
| 	client := &http.Client{ | ||||
| 		Timeout: 5 * time.Second, | ||||
| 	} | ||||
| @@ -130,19 +132,19 @@ func (p *remoteFileProvider) hasChanged() (bool, error) { | ||||
| 	return resp.StatusCode == 200, nil | ||||
| } | ||||
|  | ||||
| type localFileProvider struct { | ||||
| type LocalFileProvider struct { | ||||
| 	*file.File | ||||
|  | ||||
| 	order []string | ||||
| } | ||||
|  | ||||
| func LocalFileProvider(u *url.URL) *localFileProvider { | ||||
| 	return &localFileProvider{ | ||||
| func NewLocalFileProvider(u *url.URL) *LocalFileProvider { | ||||
| 	return &LocalFileProvider{ | ||||
| 		File: file.Provider(u.Path), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (p *localFileProvider) ReadBytes() ([]byte, error) { | ||||
| func (p *LocalFileProvider) ReadBytes() ([]byte, error) { | ||||
| 	buf, err := p.File.ReadBytes() | ||||
|  | ||||
| 	if err == nil { | ||||
| @@ -152,6 +154,6 @@ func (p *localFileProvider) ReadBytes() ([]byte, error) { | ||||
| 	return buf, err | ||||
| } | ||||
|  | ||||
| func (p *localFileProvider) Order() []string { | ||||
| func (p *LocalFileProvider) Order() []string { | ||||
| 	return p.order | ||||
| } | ||||
|   | ||||
| @@ -94,7 +94,7 @@ func (p *lookupProvider) SubProviders() []koanf.Provider { | ||||
| 		if err != nil { | ||||
| 			p.logger.Warn("failed to parse URL for configuration file", zap.Error(err)) | ||||
| 		} else { | ||||
| 			ps = append(ps, RemoteFileProvider(u)) | ||||
| 			ps = append(ps, NewRemoteFileProvider(u)) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -83,7 +83,7 @@ type Provider struct { | ||||
| // - command line flags | ||||
| func (c *Config) GetProviders() ([]koanf.Provider, error) { | ||||
| 	ps := []koanf.Provider{ | ||||
| 		StructsProvider(&DefaultSettings, "koanf"), | ||||
| 		NewStructsProvider(&DefaultSettings, "koanf"), | ||||
| 		WireGuardProvider(), | ||||
| 	} | ||||
|  | ||||
| @@ -97,12 +97,13 @@ func (c *Config) GetProviders() ([]koanf.Provider, error) { | ||||
| 	if len(c.Files) == 0 { | ||||
| 		searchPath := []string{"/etc", "/etc/cunicu"} | ||||
|  | ||||
| 		if cwd, err := os.Getwd(); err != nil { | ||||
| 		cwd, err := os.Getwd() | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("failed to get working directory") | ||||
| 		} else { | ||||
| 			searchPath = append(searchPath, cwd) | ||||
| 		} | ||||
|  | ||||
| 		searchPath = append(searchPath, cwd) | ||||
|  | ||||
| 		if cfgDir := os.Getenv("CUNICU_CONFIG_DIR"); cfgDir != "" { | ||||
| 			searchPath = append(searchPath, cfgDir) | ||||
| 		} | ||||
| @@ -125,9 +126,9 @@ func (c *Config) GetProviders() ([]koanf.Provider, error) { | ||||
| 		var p koanf.Provider | ||||
| 		switch u.Scheme { | ||||
| 		case "http", "https": | ||||
| 			p = RemoteFileProvider(u) | ||||
| 			p = NewRemoteFileProvider(u) | ||||
| 		case "": | ||||
| 			p = LocalFileProvider(u) | ||||
| 			p = NewLocalFileProvider(u) | ||||
| 		default: | ||||
| 			return nil, fmt.Errorf("unsupported scheme '%s' for config file", u.Scheme) | ||||
| 		} | ||||
| @@ -138,7 +139,7 @@ func (c *Config) GetProviders() ([]koanf.Provider, error) { | ||||
| 	// Add a runtime configuration file if it exists | ||||
| 	if fi, err := os.Stat(RuntimeConfigFile); err == nil && !fi.IsDir() { | ||||
| 		ps = append(ps, | ||||
| 			LocalFileProvider(&url.URL{ | ||||
| 			NewLocalFileProvider(&url.URL{ | ||||
| 				Path: RuntimeConfigFile, | ||||
| 			}), | ||||
| 		) | ||||
|   | ||||
| @@ -41,7 +41,7 @@ func (s *Source) Load() error { | ||||
| func load(p koanf.Provider) (*koanf.Koanf, []string, error) { | ||||
| 	var q koanf.Parser | ||||
| 	switch p.(type) { | ||||
| 	case *remoteFileProvider, *localFileProvider: | ||||
| 	case *RemoteFileProvider, *LocalFileProvider: | ||||
| 		q = yaml.Parser() | ||||
| 	default: | ||||
| 		q = nil | ||||
| @@ -68,9 +68,11 @@ func load(p koanf.Provider) (*koanf.Koanf, []string, error) { | ||||
|  | ||||
| 	if s, ok := p.(SubProvidable); ok { | ||||
| 		for _, p := range s.SubProviders() { | ||||
| 			if d, m, err := load(p); err != nil { | ||||
| 			d, m, err := load(p) | ||||
| 			if err != nil { | ||||
| 				return nil, nil, err | ||||
| 			} else { | ||||
| 			} | ||||
|  | ||||
| 			if err := k.Merge(d); err != nil { | ||||
| 				return nil, nil, fmt.Errorf("failed to merge config: %w", err) | ||||
| 			} | ||||
| @@ -78,7 +80,6 @@ func load(p koanf.Provider) (*koanf.Koanf, []string, error) { | ||||
| 			o = append(o, m...) | ||||
| 		} | ||||
| 	} | ||||
| 	} | ||||
|  | ||||
| 	return k, o, nil | ||||
| } | ||||
|   | ||||
| @@ -4,24 +4,24 @@ import ( | ||||
| 	"errors" | ||||
| ) | ||||
|  | ||||
| type structsProvider struct { | ||||
| type StructsProvider struct { | ||||
| 	value any | ||||
| 	tag   string | ||||
| } | ||||
|  | ||||
| // StructsProvider is very similar koanf's struct provider | ||||
| // but slightly adjusted to our needs. | ||||
| func StructsProvider(v any, t string) *structsProvider { | ||||
| 	return &structsProvider{ | ||||
| func NewStructsProvider(v any, t string) *StructsProvider { | ||||
| 	return &StructsProvider{ | ||||
| 		value: v, | ||||
| 		tag:   t, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (p *structsProvider) ReadBytes() ([]byte, error) { | ||||
| func (p *StructsProvider) ReadBytes() ([]byte, error) { | ||||
| 	return nil, errors.New("this provider requires no parser") | ||||
| } | ||||
|  | ||||
| func (p *structsProvider) Read() (map[string]any, error) { | ||||
| func (p *StructsProvider) Read() (map[string]any, error) { | ||||
| 	return Map(p.value, p.tag), nil | ||||
| } | ||||
|   | ||||
| @@ -93,7 +93,9 @@ func (d *Daemon) Run() error { | ||||
|  | ||||
| 	go d.watcher.Watch() | ||||
|  | ||||
| 	d.watcher.Sync() | ||||
| 	if err := d.watcher.Sync(); err != nil { | ||||
| 		return fmt.Errorf("initial sync failed: %w", err) | ||||
| 	} | ||||
|  | ||||
| out: | ||||
| 	for { | ||||
|   | ||||
| @@ -1,4 +1,3 @@ | ||||
| // Package feat contains several sub-packages each implementing a dedicated feature. | ||||
| package daemon | ||||
|  | ||||
| import ( | ||||
|   | ||||
| @@ -194,7 +194,7 @@ func (e *Interface) PeerByPublicKey(pk crypto.Key) *Peer { | ||||
| // Endpoint returns the best guess about our own endpoint | ||||
| func (e *Interface) Endpoint() (*net.UDPAddr, error) { | ||||
| 	var ep *net.UDPAddr | ||||
| 	var bestPrio uint32 = 0 | ||||
| 	var bestPrio uint32 | ||||
|  | ||||
| 	for _, p := range e.Peers { | ||||
| 		cs, err := p.agent.GetLocalCandidates() | ||||
|   | ||||
| @@ -400,14 +400,17 @@ func (p *Peer) Marshal() *protoepdisc.Peer { | ||||
| 		} | ||||
|  | ||||
| 		for _, cps := range p.agent.GetCandidatePairsStats() { | ||||
| 			cps := cps | ||||
| 			q.CandidatePairStats = append(q.CandidatePairStats, protoepdisc.NewCandidatePairStats(&cps)) | ||||
| 		} | ||||
|  | ||||
| 		for _, cs := range p.agent.GetLocalCandidatesStats() { | ||||
| 			cs := cs | ||||
| 			q.LocalCandidateStats = append(q.LocalCandidateStats, protoepdisc.NewCandidateStats(&cs)) | ||||
| 		} | ||||
|  | ||||
| 		for _, cs := range p.agent.GetRemoteCandidatesStats() { | ||||
| 			cs := cs | ||||
| 			q.RemoteCandidateStats = append(q.RemoteCandidateStats, protoepdisc.NewCandidateStats(&cs)) | ||||
| 		} | ||||
| 	} | ||||
| @@ -429,16 +432,16 @@ func (p *Peer) Reachability() protoepdisc.Reachability { | ||||
| 		case ice.CandidateTypeServerReflexive: | ||||
| 			if cp.Remote.NetworkType().IsTCP() { | ||||
| 				return protoepdisc.Reachability_DIRECT_TCP | ||||
| 			} else { | ||||
| 				return protoepdisc.Reachability_DIRECT_UDP | ||||
| 			} | ||||
|  | ||||
| 			return protoepdisc.Reachability_DIRECT_UDP | ||||
|  | ||||
| 		case ice.CandidateTypeRelay: | ||||
| 			if cp.Remote.NetworkType().IsTCP() { | ||||
| 				return protoepdisc.Reachability_RELAY_TCP | ||||
| 			} else { | ||||
| 				return protoepdisc.Reachability_RELAY_UDP | ||||
| 			} | ||||
|  | ||||
| 			return protoepdisc.Reachability_RELAY_UDP | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -104,6 +104,8 @@ func (pd *Interface) sendPeerDescription(chg pdiscproto.PeerDescriptionChange, p | ||||
|  | ||||
| 	// Static addresses | ||||
| 	for _, addr := range pd.Settings.Addresses { | ||||
| 		addr := addr | ||||
|  | ||||
| 		_, bits := addr.Mask.Size() | ||||
| 		addr.Mask = net.CIDRMask(bits, bits) | ||||
|  | ||||
| @@ -112,6 +114,8 @@ func (pd *Interface) sendPeerDescription(chg pdiscproto.PeerDescriptionChange, p | ||||
|  | ||||
| 	// Auto-generated prefixes | ||||
| 	for _, pfx := range pd.Settings.Prefixes { | ||||
| 		pfx := pfx | ||||
|  | ||||
| 		addr := pk.IPAddress(pfx) | ||||
|  | ||||
| 		_, bits := addr.Mask.Size() | ||||
|   | ||||
| @@ -25,7 +25,10 @@ func (rs *Interface) OnPeerAdded(p *core.Peer) { | ||||
| 		rs.gwMap[gw] = p | ||||
| 	} | ||||
|  | ||||
| 	rs.syncKernel() // Initial sync | ||||
| 	// Initial sync | ||||
| 	if err := rs.syncKernel(); err != nil { | ||||
| 		rs.logger.Error("Failed to synchronize kernel routing table", zap.Error(err)) | ||||
| 	} | ||||
|  | ||||
| 	p.OnModified(rs) | ||||
| } | ||||
|   | ||||
| @@ -65,7 +65,7 @@ func (p *Peer) Dump(wr io.Writer, verbosity int) error { | ||||
| 	} | ||||
|  | ||||
| 	if p.SelectedCandidatePair != nil { | ||||
| 		if _, err := terminal.FprintKV(wr, "candidate-pair", p.SelectedCandidatePair.ToString()); err != nil { | ||||
| 		if _, err := terminal.FprintKV(wr, "candidate pair", p.SelectedCandidatePair.ToString()); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
| @@ -84,7 +84,7 @@ func (s *EndpointDiscoveryServer) RestartPeer(ctx context.Context, params *rpcpr | ||||
| } | ||||
|  | ||||
| func (s *EndpointDiscoveryServer) SendConnectionStates(stream rpcproto.Daemon_StreamEventsServer) { | ||||
| 	s.daemon.ForEachInterface(func(di *daemon.Interface) error { | ||||
| 	if err := s.daemon.ForEachInterface(func(di *daemon.Interface) error { | ||||
| 		i := s.Interface(di) | ||||
|  | ||||
| 		for _, p := range i.Peers { | ||||
| @@ -102,12 +102,14 @@ func (s *EndpointDiscoveryServer) SendConnectionStates(stream rpcproto.Daemon_St | ||||
| 			if err := stream.Send(e); err == io.EOF { | ||||
| 				continue | ||||
| 			} else if err != nil { | ||||
| 				s.logger.Error("Failed to send", zap.Error(err)) | ||||
| 				s.logger.Error("Failed to send connection states", zap.Error(err)) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		return nil | ||||
| 	}) | ||||
| 	}); err != nil { | ||||
| 		s.logger.Error("Failed to send connection states", zap.Error(err)) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (s *EndpointDiscoveryServer) OnConnectionStateChange(p *epdisc.Peer, new, prev icex.ConnectionState) { | ||||
|   | ||||
| @@ -14,7 +14,7 @@ function request() { | ||||
| } | ||||
|  | ||||
| function undraft_release() { | ||||
|     request releases/$1 -X PATCH -d '{ "draft": false }'  | \ | ||||
|     request "releases/$1" -X PATCH -d '{ "draft": false }'  | \ | ||||
|     jq . | ||||
| } | ||||
|  | ||||
| @@ -28,7 +28,7 @@ function download_asset() { | ||||
|  | ||||
|     curl --silent \ | ||||
|          --location \ | ||||
|          --output ${ASSET_NAME} \ | ||||
|          --output "${ASSET_NAME}" \ | ||||
|          --header "Authorization: Bearer ${GITHUB_TOKEN}" \ | ||||
|          --header "Accept:application/octet-stream" \ | ||||
|          "https://api.github.com/repos/${REPO}/releases/assets/${ASSET_ID}" | ||||
| @@ -37,7 +37,7 @@ function download_asset() { | ||||
| function upload_asset() { | ||||
|     RELEASE_ID=$1 | ||||
|     FILENAME=$2 | ||||
|     MIME_TYPE=$(file -b --mime-type ${FILENAME}) | ||||
|     MIME_TYPE=$(file -b --mime-type "${FILENAME}") | ||||
|  | ||||
|     curl --silent \ | ||||
|          --location \ | ||||
| @@ -45,7 +45,7 @@ function upload_asset() { | ||||
|          --header "Content-Type: ${MIME_TYPE}" \ | ||||
|          --header "Accept: application/vnd.github+json" \ | ||||
|          --header "Authorization: Bearer ${GITHUB_TOKEN}" \ | ||||
|          --data-binary @${FILENAME} \ | ||||
|          --data-binary "@${FILENAME}" \ | ||||
|          "https://uploads.github.com/repos/${REPO}/releases/${RELEASE_ID}/assets?name=${FILENAME}" | \ | ||||
|     jq . | ||||
| } | ||||
|   | ||||
| @@ -2,39 +2,39 @@ | ||||
|  | ||||
| This website is built using [Docusaurus 2](https://docusaurus.io/), a modern static website generator. | ||||
|  | ||||
| ### Installation | ||||
| ## Installation | ||||
|  | ||||
| ``` | ||||
| ```bash | ||||
| $ yarn | ||||
| ``` | ||||
|  | ||||
| ### Local Development | ||||
| ## Local Development | ||||
|  | ||||
| ``` | ||||
| ```bash | ||||
| $ yarn start | ||||
| ``` | ||||
|  | ||||
| This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server. | ||||
|  | ||||
| ### Build | ||||
| ## Build | ||||
|  | ||||
| ``` | ||||
| ```bash | ||||
| $ yarn build | ||||
| ``` | ||||
|  | ||||
| This command generates static content into the `build` directory and can be served using any static contents hosting service. | ||||
|  | ||||
| ### Deployment | ||||
| ## Deployment | ||||
|  | ||||
| Using SSH: | ||||
|  | ||||
| ``` | ||||
| ```bash | ||||
| $ USE_SSH=true yarn deploy | ||||
| ``` | ||||
|  | ||||
| Not using SSH: | ||||
|  | ||||
| ``` | ||||
| ```bash | ||||
| $ GIT_USER=<Your GitHub username> yarn deploy | ||||
| ``` | ||||
|  | ||||
|   | ||||
| @@ -23,7 +23,7 @@ The project has now its dedicated [website](https://cunicu.li), [GitHub organiza | ||||
| Feel free to follow us there for updates! | ||||
|  | ||||
| You might also have realized that the project name has changed. We decided to rebrand from the previous name _wice_ to avoid any potential trademark issues with the WireGuard project as well as another small German company named _WICE_. | ||||
| The project name _cunīcu_ [kʊˈniːkʊ] is derived from the [latin noun cunīculus](https://en.wiktionary.org/wiki/cuniculus#Latin) which means rabbit, a rabbit burrow or underground tunnel. We have choosen it as a name for this project as _cunīcu_ builds tunnels between otherwise hard to reach network locations. | ||||
| The project name _cunīcu_ \[kʊˈniːkʊ\] is derived from the [latin noun cunīculus](https://en.wiktionary.org/wiki/cuniculus#Latin) which means rabbit, a rabbit burrow or underground tunnel. We have choosen it as a name for this project as _cunīcu_ builds tunnels between otherwise hard to reach network locations. | ||||
|  | ||||
| This also gave us the opportunity to redesign the logo which you find further down in the sticker design. | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Steffen Vogel
					Steffen Vogel