Re-sign JWT tokens for safer server deployments
This commit is contained in:
parent
d6860160f4
commit
fb11295168
13
README.md
13
README.md
|
@ -25,7 +25,11 @@ It is very much in the style of the old-school Flash based webcam chat rooms of
|
|||
* Specify multiple Public Channels that all users have access to.
|
||||
* Users can open direct message (one-on-one) conversations with each other.
|
||||
* No long-term server side state: messages are pushed out as they come in.
|
||||
* Users may share pictures and GIFs from their computer, which are pushed out as `data:` URLs (images scaled and metadata stripped by server) directly to connected chatters with no storage required.
|
||||
* Users may broadcast their webcam which shows a camera icon by their name in the Who List. Users may click on those icons to open multiple camera feeds of other users they are interested in.
|
||||
* Mutual webcam options: users may opt that anyone who views their cam must also be sharing their own camera first.
|
||||
* Users may mark their own cameras as explicit/NSFW which marks the icon in red so other users can get a warning before clicking in (if NSFW is enabled in the settings.toml)
|
||||
* Users may boot people off their camera, and to the booted person it appears the same as if the broadcaster had turned their camera off completely - the chat server lies about the camera status so the booted user can't easily tell they'd been booted.
|
||||
* Mobile friendly: works best on iPads and above but adapts to smaller screens well.
|
||||
* WebRTC means peer-to-peer video streaming so cheap on hosting costs!
|
||||
* Simple integration with your existing userbase via signed JWT tokens.
|
||||
|
@ -44,12 +48,16 @@ Some important features still lacking:
|
|||
On first run it will create the default settings.toml file for you which you may then customize to your liking:
|
||||
|
||||
```toml
|
||||
Version = 2
|
||||
Title = "BareRTC"
|
||||
Branding = "BareRTC"
|
||||
WebsiteURL = "https://www.example.com"
|
||||
UseXForwardedFor = true
|
||||
CORSHosts = ["https://www.example.com"]
|
||||
PermitNSFW = true
|
||||
UseXForwardedFor = true
|
||||
WebSocketReadLimit = 41943040
|
||||
MaxImageWidth = 1280
|
||||
PreviewImageWidth = 360
|
||||
|
||||
[JWT]
|
||||
Enabled = false
|
||||
|
@ -79,6 +87,9 @@ A description of the config directives includes:
|
|||
* **UseXForwardedFor**: set it to true and (for logging) the user's remote IP will use the X-Real-IP header or the first address in X-Forwarded-For. Set this if you run the app behind a proxy like nginx if you want IPs not to be all localhost.
|
||||
* **CORSHosts**: your website's domain names that will be allowed to access [JSON APIs](#JSON APIs), like `/api/statistics`.
|
||||
* **PermitNSFW**: for user webcam streams, expressly permit "NSFW" content if the user opts in to mark their feed as such. Setting this will enable pop-up modals regarding NSFW video and give broadcasters an opt-in button, which will warn other users before they click in to watch.
|
||||
* **WebSocketReadLimit**: sets a size limit for WebSocket messages - it essentially also caps the max upload size for shared images (add a buffer as images will be base64 encoded on upload).
|
||||
* **MaxImageWidth**: for pictures shared in chat the server will resize them down to no larger than this width for the full size view.
|
||||
* **PreviewImageWidth**: to not flood the chat, the image in chat is this wide and users can click it to see the MaxImageWidth in a lightbox modal.
|
||||
* **JWT**: settings for JWT [Authentication](#authentication).
|
||||
* Enabled (bool): activate the JWT token authentication feature.
|
||||
* Strict (bool): if true, **only** valid signed JWT tokens may log in. If false, users with no/invalid token can enter their own username without authentication.
|
||||
|
|
|
@ -2,4 +2,4 @@ package barertc
|
|||
|
||||
import "time"
|
||||
|
||||
const PingInterval = 15 * time.Second
|
||||
const PingInterval = 30 * time.Second
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"html/template"
|
||||
"time"
|
||||
|
||||
"git.kirsle.net/apps/barertc/pkg/config"
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
|
@ -53,3 +54,18 @@ func ParseAndValidate(tokenStr string) (*Claims, bool, error) {
|
|||
|
||||
return claims, authOK, nil
|
||||
}
|
||||
|
||||
// ReSign will sign a new JWT token for existing claims. The chat server does this to send refreshed tokens
|
||||
// to the front-end so the server can reboot gracefully, clients reconnect and not be told their auth had
|
||||
// expired. New token expires after 5 minutes.
|
||||
func (c Claims) ReSign() (string, error) {
|
||||
// Refresh timestamps.
|
||||
c.ExpiresAt = jwt.NewNumericDate(time.Now().Add(5 * time.Minute))
|
||||
c.IssuedAt = jwt.NewNumericDate(time.Now())
|
||||
c.NotBefore = jwt.NewNumericDate(time.Now())
|
||||
|
||||
// Generate the signed token and return it.
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
|
||||
ss, err := token.SignedString([]byte(config.Current.JWT.SecretKey))
|
||||
return ss, err
|
||||
}
|
||||
|
|
|
@ -188,8 +188,19 @@ func (s *Server) WebSocket() http.HandlerFunc {
|
|||
return
|
||||
}
|
||||
case <-pinger.C:
|
||||
// Send a ping, and a refreshed JWT token if the user sent one.
|
||||
var token string
|
||||
if sub.JWTClaims != nil {
|
||||
if jwt, err := sub.JWTClaims.ReSign(); err != nil {
|
||||
log.Error("ReSign JWT token for %s: %s", sub.Username, err)
|
||||
} else {
|
||||
token = jwt
|
||||
}
|
||||
}
|
||||
|
||||
sub.SendJSON(Message{
|
||||
Action: ActionPing,
|
||||
Action: ActionPing,
|
||||
JWTToken: token,
|
||||
})
|
||||
case <-ctx.Done():
|
||||
pinger.Stop()
|
||||
|
|
|
@ -608,6 +608,15 @@ const app = Vue.createApp({
|
|||
this.disconnect = true;
|
||||
break;
|
||||
case "ping":
|
||||
// New JWT token?
|
||||
if (msg.jwt) {
|
||||
this.jwt.token = msg.jwt;
|
||||
}
|
||||
|
||||
// Reset disconnect retry counter: if we were on long enough to get
|
||||
// a ping, we're well connected and can reconnect no matter how many
|
||||
// times the chat server is rebooted.
|
||||
this.disconnectCount = 0;
|
||||
break;
|
||||
default:
|
||||
console.error("Unexpected action: %s", JSON.stringify(msg));
|
||||
|
|
Loading…
Reference in New Issue
Block a user