Skip to content

jleeh/websocket-proxy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

WebSocket Proxy

Lightweight WebSocket proxy with API key management built on top of gorilla/websockets. This can either be imported for use in your own implementations with the http.Handler interface, or installed directly to be used as a CLI.

Supported authentication methods:

  • Headers (X-API-KEY)
  • GET Param (apikey)

Supported key management tools:

  • Local file
  • AWS Secrets Manager

Install & Build

go get -d github.com/jleeh/websocket-proxy && go build -o $GOPATH/bin/websocket-proxy

Running the Proxy

Docker

docker run -e SERVER=ws://localhost:3000 -it jonnyh/websocket-proxy:latest

Local

You can run the WebSocket proxy by just running the built binary:

./websocket-proxy

Configure

Configuration for the CLI is via Viper, so configuration variables can be passed in via environment variables or file.

Example configuration:

port: 8080
server: ws://localhost:3000
auth_type: header
key_manager_type: file
key_identifier: /home/me/keys.json
allowed_origins:
  - localhost
  - google.com

Example .env file:

PORT=80
SERVER=ws://localhost:3000
AUTH_TYPE=header
KEY_MANAGER_TYPE=file
KEY_IDENTIFIER=/home/me/keys.json
ALLOWED_ORIGINS=localhost,google.com

Using AWS Secrets Manager

Change the key_manager_type configuration variable to aws_sm and then change the key_identifier to the name of the secret in AWS.

Custom Example

go get github.com/jleeh/websocket-proxy/proxy
package main

import (
	"github.com/jleeh/websocket-proxy/proxy"
	"log"
	"net/http"
	"net/url"
)

func main() {
	u, _ := url.Parse("ws://localhost:3000")
	wp, _ := proxy.NewSimpleProxy(u)
	
	http.HandleFunc("/", wp.Handler)
	log.Fatal(http.ListenAndServe(":80", nil))
}

Extending Authentication

Interface:

type Auth interface {
	Authenticate(*http.Request, KeyManager) bool
}

Implementation example (header):

// Header is the Auth implementation that requires `X-API-KEY` to be set
// in the request headers
type Header struct{}

// Authenticate takes the `X-API-KEY` in the request headers and then authenticates
// it with the KeyManager
func (p *Header) Authenticate(r *http.Request, km KeyManager) bool {
	key := r.Header.Get("X-API-KEY")
	return km.ValidateKey(key)
}

You can create your own implementation of an Auth type to then pass into the proxy.NewProxy(...) method.

Extending KeyManager

Interface:

type KeyManager interface {
	ValidateKey(string) bool
	FetchKeys() error
	setIdentifier(string)
}

Implementation example (file):

// File manages keys on the local disk
type File struct {
	id string
	keys []string
}

// ValidateKey returns a boolean to whether a key given is present in the file
func (f *File) ValidateKey(key string) bool {
	for _, k := range f.keys {
		if k == key {
			return true
		}
	}
	return false
}

// FetchKeys sets the keys from the file on local disk
func (f *File) FetchKeys() error {
	if file, err := os.Open(f.id); err != nil {
		return err
	} else if b, err := ioutil.ReadAll(file); err != nil {
		return err
	} else if err := json.Unmarshal(b, &f.keys); err != nil {
		return err
	}
	return nil
}

func (f *File) setIdentifier(id string) {
	f.id = id
}

You can create your own implementation of a KeyManager type to then pass into the proxy.NewProxy(...) method.

About

Lightweight WebSocket proxy with API key management.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published