Start adding room access restrictions
So far only PIN and Open modes are implemented. It uses a session cookie to store the validity of the pin/password. The "Enter pin" page has some unreadable messages on it right now, but it kinda works.
This commit is contained in:
parent
bdfa75f8bc
commit
82149cda0c
|
@ -241,6 +241,19 @@ var commands = &CommandControl{
|
|||
return ""
|
||||
},
|
||||
},
|
||||
|
||||
common.CNPin.String(): Command{
|
||||
HelpText: "Display the current room access type and pin/password (if applicable).",
|
||||
Function: func(cl *Client, args []string) string {
|
||||
switch settings.RoomAccess {
|
||||
case AccessPin:
|
||||
return "Room is secured via PIN. Current PIN: " + settings.RoomAccessPin
|
||||
case AccessRequest:
|
||||
return "Room is secured via access requests. Users must request to be granted access."
|
||||
}
|
||||
return "Room is open access. Anybody can join."
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
admin: map[string]Command{
|
||||
|
@ -291,6 +304,62 @@ var commands = &CommandControl{
|
|||
return "Single use password: " + password
|
||||
},
|
||||
},
|
||||
|
||||
common.CNNewPin.String(): Command{
|
||||
HelpText: "Generate a room acces new pin",
|
||||
Function: func(cl *Client, args []string) string {
|
||||
if settings.RoomAccess != AccessPin {
|
||||
return "Room is not restricted by Pin. (" + string(settings.RoomAccess) + ")"
|
||||
}
|
||||
|
||||
pin, err := settings.generateNewPin()
|
||||
if err != nil {
|
||||
return "Unable to generate new pin: " + err.Error()
|
||||
}
|
||||
|
||||
fmt.Println("New room access pin: ", pin)
|
||||
return "New access pin: " + pin
|
||||
},
|
||||
},
|
||||
|
||||
common.CNRoomAccess.String(): Command{
|
||||
HelpText: "Change the room access type.",
|
||||
Function: func(cl *Client, args []string) string {
|
||||
// Print current access type if no arguments given
|
||||
if len(args) == 0 {
|
||||
return "Current room access type: " + string(settings.RoomAccess)
|
||||
}
|
||||
|
||||
switch AccessMode(strings.ToLower(args[0])) {
|
||||
case AccessOpen:
|
||||
settings.RoomAccess = AccessOpen
|
||||
return "Room access set to open"
|
||||
|
||||
case AccessPin:
|
||||
// A pin/password was provided, use it.
|
||||
if len(args) == 2 {
|
||||
settings.RoomAccessPin = args[1]
|
||||
|
||||
// A pin/password was not provided, generate a new one.
|
||||
} else {
|
||||
_, err := settings.generateNewPin()
|
||||
if err != nil {
|
||||
fmt.Println("Error generating new access pin: ", err.Error())
|
||||
return "Unable to generate a new pin, access unchanged: " + err.Error()
|
||||
}
|
||||
}
|
||||
settings.RoomAccess = AccessPin
|
||||
return "Room access set to Pin: " + settings.RoomAccessPin
|
||||
|
||||
case AccessRequest:
|
||||
settings.RoomAccess = AccessRequest
|
||||
return "Room access set to request. WARNING: this isn't implemented yet."
|
||||
|
||||
default:
|
||||
return "Invalid access mode"
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -29,20 +29,23 @@ var (
|
|||
CNBan ChatCommandNames = []string{"ban"}
|
||||
CNUnban ChatCommandNames = []string{"unban"}
|
||||
CNPurge ChatCommandNames = []string{"purge"}
|
||||
CNPin ChatCommandNames = []string{"pin", "password"}
|
||||
// Admin Commands
|
||||
CNMod ChatCommandNames = []string{"mod"}
|
||||
CNReloadPlayer ChatCommandNames = []string{"reloadplayer"}
|
||||
CNReloadEmotes ChatCommandNames = []string{"reloademotes"}
|
||||
CNModpass ChatCommandNames = []string{"modpass"}
|
||||
CNNewPin ChatCommandNames = []string{"newpin", "newpassword"}
|
||||
CNRoomAccess ChatCommandNames = []string{"changeaccess", "hodor"}
|
||||
)
|
||||
|
||||
var ChatCommands = []ChatCommandNames{
|
||||
// User
|
||||
CNMe, CNHelp, CNCount, CNColor, CNWhoAmI, CNAuth, CNUsers, CNNick,
|
||||
// Mod
|
||||
CNSv, CNPlaying, CNUnmod, CNKick, CNBan, CNUnban, CNPurge,
|
||||
CNSv, CNPlaying, CNUnmod, CNKick, CNBan, CNUnban, CNPurge, CNPin,
|
||||
// Admin
|
||||
CNMod, CNReloadPlayer, CNReloadEmotes, CNModpass,
|
||||
CNMod, CNReloadPlayer, CNReloadEmotes, CNModpass, CNRoomAccess,
|
||||
}
|
||||
|
||||
func GetFullChatCommand(c string) string {
|
||||
|
|
118
handlers.go
118
handlers.go
|
@ -153,6 +153,94 @@ func wsHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}()
|
||||
}
|
||||
|
||||
// returns if it's OK to proceed
|
||||
func checkRoomAccess(w http.ResponseWriter, r *http.Request) bool {
|
||||
session, err := sstore.Get(r, "moviesession")
|
||||
if err != nil {
|
||||
fmt.Printf("Unable to get session for client %s: %v\n", r.RemoteAddr, err)
|
||||
http.Error(w, "Unable to get session data", http.StatusInternalServerError)
|
||||
return false
|
||||
}
|
||||
|
||||
if settings.RoomAccess == AccessPin {
|
||||
pin := session.Values["pin"]
|
||||
// No pin found in session
|
||||
if pin == nil || len(pin.(string)) == 0 {
|
||||
if r.Method == "POST" {
|
||||
// Check for correct pin
|
||||
err = r.ParseForm()
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing form")
|
||||
http.Error(w, "Unable to get session data", http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
postPin := r.Form.Get("txtInput")
|
||||
fmt.Printf("Received pin: %s\n", postPin)
|
||||
if postPin == settings.RoomAccessPin {
|
||||
// Pin is correct. Save it to session and return true.
|
||||
session.Values["pin"] = settings.RoomAccessPin
|
||||
session.Save(r, w)
|
||||
return true
|
||||
}
|
||||
// Pin is incorrect.
|
||||
handlePinTemplate(w, r, "Incorrect PIN")
|
||||
return false
|
||||
}
|
||||
// nope. display pin entry and return
|
||||
handlePinTemplate(w, r, "")
|
||||
return false
|
||||
}
|
||||
|
||||
// Pin found in session, but it has changed since last time.
|
||||
if pin.(string) != settings.RoomAccessPin {
|
||||
// Clear out the old pin.
|
||||
session.Values["pin"] = nil
|
||||
session.Save(r, w)
|
||||
|
||||
// Prompt for new one.
|
||||
handlePinTemplate(w, r, "Pin has changed. Enter new PIN.")
|
||||
return false
|
||||
}
|
||||
|
||||
// Correct pin found in session
|
||||
return true
|
||||
}
|
||||
|
||||
// TODO: this.
|
||||
if settings.RoomAccess == AccessRequest {
|
||||
http.Error(w, "Requesting access not implemented yet", http.StatusNotImplemented)
|
||||
return false
|
||||
}
|
||||
|
||||
// Room is open.
|
||||
return true
|
||||
}
|
||||
|
||||
func handlePinTemplate(w http.ResponseWriter, r *http.Request, errorMessage string) {
|
||||
t, err := template.ParseFiles("./static/base.html", "./static/thedoor.html")
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing template file: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
type Data struct {
|
||||
Title string
|
||||
SubmitText string
|
||||
Error string
|
||||
}
|
||||
|
||||
data := Data{
|
||||
Title: "Enter Pin",
|
||||
SubmitText: "Submit Pin",
|
||||
Error: errorMessage,
|
||||
}
|
||||
|
||||
err = t.Execute(w, data)
|
||||
if err != nil {
|
||||
fmt.Printf("Error executing file, %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func handleHelpTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
t, err := template.ParseFiles("./static/base.html", "./static/help.html")
|
||||
if err != nil {
|
||||
|
@ -186,7 +274,37 @@ func handleHelpTemplate(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
func handlePin(w http.ResponseWriter, r *http.Request) {
|
||||
session, err := sstore.Get(r, "moviesession")
|
||||
if err != nil {
|
||||
fmt.Printf("Unable to get session: %v\n", err)
|
||||
}
|
||||
|
||||
val := session.Values["pin"]
|
||||
if val == nil {
|
||||
session.Values["pin"] = "1234"
|
||||
err := session.Save(r, w)
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, "unable to save session: %v", err)
|
||||
}
|
||||
fmt.Fprint(w, "Pin was not set")
|
||||
fmt.Println("pin was not set")
|
||||
} else {
|
||||
fmt.Fprintf(w, "pin set: %v", val)
|
||||
fmt.Printf("pin is set: %v\n", val)
|
||||
}
|
||||
}
|
||||
|
||||
func handleIndexTemplate(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Printf("RoomAcces: %s\n", settings.RoomAccess)
|
||||
if settings.RoomAccess != AccessOpen {
|
||||
if !checkRoomAccess(w, r) {
|
||||
fmt.Println("Denied access")
|
||||
return
|
||||
}
|
||||
fmt.Println("Granted access")
|
||||
}
|
||||
|
||||
t, err := template.ParseFiles("./static/base.html", "./static/main.html")
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing template file, %v\n", err)
|
||||
|
|
3
main.go
3
main.go
|
@ -51,6 +51,8 @@ func main() {
|
|||
|
||||
fmt.Println("Stream key: ", settings.GetStreamKey())
|
||||
fmt.Println("Admin password: ", settings.AdminPassword)
|
||||
fmt.Println("RoomAccess: ", settings.RoomAccess)
|
||||
fmt.Println("RoomAccessPin: ", settings.RoomAccessPin)
|
||||
fmt.Println("Listen and serve ", addr)
|
||||
|
||||
go startServer()
|
||||
|
@ -82,6 +84,7 @@ func startServer() {
|
|||
http.HandleFunc("/chat", handleIndexTemplate)
|
||||
http.HandleFunc("/video", handleIndexTemplate)
|
||||
http.HandleFunc("/help", handleHelpTemplate)
|
||||
http.HandleFunc("/pin", handlePin)
|
||||
|
||||
http.HandleFunc("/", handleDefault)
|
||||
|
||||
|
|
56
settings.go
56
settings.go
|
@ -6,13 +6,17 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/sessions"
|
||||
)
|
||||
|
||||
var settings *Settings
|
||||
var settingsMtx sync.Mutex
|
||||
var sstore *sessions.CookieStore
|
||||
|
||||
type Settings struct {
|
||||
// Non-Saved settings
|
||||
|
@ -24,11 +28,22 @@ type Settings struct {
|
|||
MaxMessageCount int
|
||||
TitleLength int // maximum length of the title that can be set with the /playing
|
||||
AdminPassword string
|
||||
Bans []BanInfo
|
||||
StreamKey string
|
||||
ListenAddress string
|
||||
Bans []BanInfo
|
||||
SessionKey string // key for session data
|
||||
RoomAccess AccessMode
|
||||
RoomAccessPin string // auto generate this,
|
||||
}
|
||||
|
||||
type AccessMode string
|
||||
|
||||
const (
|
||||
AccessOpen AccessMode = "open"
|
||||
AccessPin AccessMode = "pin"
|
||||
AccessRequest AccessMode = "request"
|
||||
)
|
||||
|
||||
type BanInfo struct {
|
||||
IP string
|
||||
Names []string
|
||||
|
@ -49,6 +64,36 @@ func init() {
|
|||
settings.TitleLength = 50
|
||||
}
|
||||
|
||||
// Is this a good way to do this? Probably not...
|
||||
if len(settings.SessionKey) == 0 {
|
||||
out := ""
|
||||
large := big.NewInt(int64(1 << 60))
|
||||
large = large.Add(large, large)
|
||||
for len(out) < 50 {
|
||||
num, err := rand.Int(rand.Reader, large)
|
||||
if err != nil {
|
||||
panic("Error generating session key: " + err.Error())
|
||||
}
|
||||
out = fmt.Sprintf("%s%X", out, num)
|
||||
}
|
||||
settings.SessionKey = out
|
||||
}
|
||||
|
||||
if len(settings.RoomAccess) == 0 {
|
||||
settings.RoomAccess = AccessOpen
|
||||
}
|
||||
|
||||
if settings.RoomAccess != AccessOpen && len(settings.RoomAccessPin) == 0 {
|
||||
settings.RoomAccessPin = "1234"
|
||||
}
|
||||
|
||||
sstore = sessions.NewCookieStore([]byte(settings.SessionKey))
|
||||
sstore.Options = &sessions.Options{
|
||||
Path: "/",
|
||||
MaxAge: 60 * 60 * 24, // one day
|
||||
SameSite: http.SameSiteStrictMode,
|
||||
}
|
||||
|
||||
// Save admin password to file
|
||||
if err = settings.Save(); err != nil {
|
||||
panic("Unable to save settings: " + err.Error())
|
||||
|
@ -174,3 +219,12 @@ func (s *Settings) GetStreamKey() string {
|
|||
}
|
||||
return s.StreamKey
|
||||
}
|
||||
|
||||
func (s *Settings) generateNewPin() (string, error) {
|
||||
num, err := rand.Int(rand.Reader, big.NewInt(int64(9999)))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
settings.RoomAccessPin = fmt.Sprintf("%04d", num)
|
||||
return settings.RoomAccessPin, nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
{{define "header"}}
|
||||
|
||||
{{end}}
|
||||
|
||||
{{define "body"}}
|
||||
<div>
|
||||
{{if .Error}}<div>{{.Error}}</div>{{end}}
|
||||
<form action="/" method="post">
|
||||
<input type="text" name="txtInput" /><br />
|
||||
<input type="submit" value="{{.SubmitText}}" />
|
||||
</form>
|
||||
</div>
|
||||
{{end}}
|
Loading…
Reference in New Issue