Add DisconnectNow API endpoint
This commit is contained in:
parent
c7ef254361
commit
96d61614f4
152
docs/API.md
152
docs/API.md
|
@ -27,16 +27,16 @@ Post your desired JWT claims to the endpoint to customize your user and it will
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"APIKey": "from settings.toml",
|
"APIKey": "from settings.toml",
|
||||||
"Claims": {
|
"Claims": {
|
||||||
"sub": "username",
|
"sub": "username",
|
||||||
"nick": "Display Name",
|
"nick": "Display Name",
|
||||||
"op": false,
|
"op": false,
|
||||||
"img": "/static/photos/avatar.png",
|
"img": "/static/photos/avatar.png",
|
||||||
"url": "/users/username",
|
"url": "/users/username",
|
||||||
"emoji": "🤖",
|
"emoji": "🤖",
|
||||||
"gender": "m"
|
"gender": "m"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -44,9 +44,9 @@ The return schema looks like:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"OK": true,
|
"OK": true,
|
||||||
"Error": "error string, omitted if none",
|
"Error": "error string, omitted if none",
|
||||||
"JWT": "jwt token string"
|
"JWT": "jwt token string"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ It requires the AdminAPIKey to post:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"APIKey": "from settings.toml"
|
"APIKey": "from settings.toml"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -66,8 +66,8 @@ The return schema looks like:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"OK": true,
|
"OK": true,
|
||||||
"Error": "error string, omitted if none"
|
"Error": "error string, omitted if none"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -110,3 +110,123 @@ The JSON response to this endpoint may look like:
|
||||||
"Error": "if error, or this key is omitted if OK"
|
"Error": "if error, or this key is omitted if OK"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## POST /api/block/now
|
||||||
|
|
||||||
|
Your website can tell BareRTC to put a block between users "now." For
|
||||||
|
example, if a user on your main website adds a block on another user,
|
||||||
|
and one or both of them are presently logged into the chat room, BareRTC
|
||||||
|
can begin enforcing the block immediately so both users will disappear
|
||||||
|
from each other's view and no longer get one another's messages.
|
||||||
|
|
||||||
|
The request body payload looks like:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"APIKey": "from your settings.toml",
|
||||||
|
"Usernames": [ "alice", "bob" ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The pair of usernames should be the two who are blocking each other, in
|
||||||
|
any order. This will put in a two-way block between those chatters.
|
||||||
|
|
||||||
|
If you provide more than two usernames, the block is put between every
|
||||||
|
combination of usernames given.
|
||||||
|
|
||||||
|
The JSON response to this endpoint may look like:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"OK": true,
|
||||||
|
"Error": "if error, or this key is omitted if OK"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## POST /api/disconnect/now
|
||||||
|
|
||||||
|
Your website can tell BareRTC to remove a user from the chat room "now"
|
||||||
|
in case that user is presently online in the chat.
|
||||||
|
|
||||||
|
The request body payload looks like:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"APIKey": "from your settings.toml",
|
||||||
|
"Usernames": [ "alice" ],
|
||||||
|
"Message": "a custom ChatServer message to send them, optional",
|
||||||
|
"Kick": false,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Message` parameter, if provided, will be sent to that user as a
|
||||||
|
ChatServer error before they are removed from the room. You can use this
|
||||||
|
to provide them context as to why they are being kicked. For example:
|
||||||
|
"You have been logged out of chat because you deactivated your profile on
|
||||||
|
the main website."
|
||||||
|
|
||||||
|
The `Kick` boolean is whether the removal should manifest to other users
|
||||||
|
in chat as a "kick" (sending a presence message of "has been kicked from
|
||||||
|
the room!"). By default (false), BareRTC will tell the user to disconnect
|
||||||
|
and it will manifest as a regular "has left the room" event to other online
|
||||||
|
chatters.
|
||||||
|
|
||||||
|
The JSON response to this endpoint may look like:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"OK": true,
|
||||||
|
"Removed": 1,
|
||||||
|
"Error": "if error, or this key is omitted if OK"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The "Removed" field is the count of users actually removed from chat; a zero
|
||||||
|
means the user was not presently online.
|
||||||
|
|
||||||
|
# Ajax Endpoints (User API)
|
||||||
|
|
||||||
|
## POST /api/profile
|
||||||
|
|
||||||
|
Fetch profile information from your main website about a user in the
|
||||||
|
chat room.
|
||||||
|
|
||||||
|
Note: this API request is done by the BareRTC chat front-end page, as an
|
||||||
|
ajax request for a current logged-in user. It backs the profile card pop-up
|
||||||
|
widget in the chat room when a user clicks on another user's profile.
|
||||||
|
|
||||||
|
The request body payload looks like:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"JWTToken": "the caller's chat jwt token",
|
||||||
|
"Username": "soandso"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The JWT token is the current chat user's token. This API only works when
|
||||||
|
your BareRTC config requires the use of JWT tokens for authorization.
|
||||||
|
|
||||||
|
BareRTC will translate the request into the
|
||||||
|
["Profile Webhook"](Webhooks.md#Profile%20Webhook) to fetch the target
|
||||||
|
user's profile from your website.
|
||||||
|
|
||||||
|
The response JSON given to the chat page from /api/profile looks like:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"OK": true,
|
||||||
|
"Error": "only on error messages",
|
||||||
|
"ProfileFields": [
|
||||||
|
{
|
||||||
|
"Name": "Age",
|
||||||
|
"Value": "30yo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Gender",
|
||||||
|
"Value": "Man"
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
128
pkg/api.go
128
pkg/api.go
|
@ -468,6 +468,134 @@ func (s *Server) BlockNow() http.HandlerFunc {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DisconnectNow (/api/disconnect/now) allows your website to remove a user from
|
||||||
|
// the chat room if they are currently online.
|
||||||
|
//
|
||||||
|
// For example: a user on your website has deactivated their account, and so
|
||||||
|
// should not be allowed to remain in the chat room.
|
||||||
|
//
|
||||||
|
// It is a POST request with a json body containing the following schema:
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// "APIKey": "from settings.toml",
|
||||||
|
// "Usernames": [ "alice", "bob" ],
|
||||||
|
// "Message": "An optional ChatServer message to send them first.",
|
||||||
|
// "Kick": false,
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// The `Message` parameter, if provided, will be sent to that user as a
|
||||||
|
// ChatServer error before they are removed from the room. You can use this
|
||||||
|
// to provide them context as to why they are being kicked. For example:
|
||||||
|
// "You have been logged out of chat because you deactivated your profile on
|
||||||
|
// the main website."
|
||||||
|
//
|
||||||
|
// The `Kick` boolean is whether the removal should manifest to other users
|
||||||
|
// in chat as a "kick" (sending a presence message of "has been kicked from
|
||||||
|
// the room!"). By default (false), BareRTC will tell the user to disconnect
|
||||||
|
// and it will manifest as a regular "has left the room" event to other online
|
||||||
|
// chatters.
|
||||||
|
func (s *Server) DisconnectNow() http.HandlerFunc {
|
||||||
|
type request struct {
|
||||||
|
APIKey string
|
||||||
|
Usernames []string
|
||||||
|
Message string
|
||||||
|
Kick bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type result struct {
|
||||||
|
OK bool
|
||||||
|
Removed int
|
||||||
|
Error string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// JSON writer for the response.
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
enc := json.NewEncoder(w)
|
||||||
|
enc.SetIndent("", " ")
|
||||||
|
|
||||||
|
// Parse the request.
|
||||||
|
if r.Method != http.MethodPost {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
enc.Encode(result{
|
||||||
|
Error: "Only POST methods allowed",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
} else if r.Header.Get("Content-Type") != "application/json" {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
enc.Encode(result{
|
||||||
|
Error: "Only application/json content-types allowed",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer r.Body.Close()
|
||||||
|
|
||||||
|
// Parse the request payload.
|
||||||
|
var (
|
||||||
|
params request
|
||||||
|
dec = json.NewDecoder(r.Body)
|
||||||
|
)
|
||||||
|
if err := dec.Decode(¶ms); err != nil {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
enc.Encode(result{
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate the API key.
|
||||||
|
if params.APIKey != config.Current.AdminAPIKey {
|
||||||
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
enc.Encode(result{
|
||||||
|
Error: "Authentication denied.",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if any of these users are online, and disconnect them from the chat.
|
||||||
|
var removed int
|
||||||
|
for _, username := range params.Usernames {
|
||||||
|
if sub, err := s.GetSubscriber(username); err == nil {
|
||||||
|
// Broadcast to everybody that the user left the chat.
|
||||||
|
message := messages.PresenceExited
|
||||||
|
if params.Kick {
|
||||||
|
message = messages.PresenceKicked
|
||||||
|
}
|
||||||
|
s.Broadcast(messages.Message{
|
||||||
|
Action: messages.ActionPresence,
|
||||||
|
Username: username,
|
||||||
|
Message: message,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Custom message to send to them?
|
||||||
|
if params.Message != "" {
|
||||||
|
sub.ChatServer(params.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disconnect them.
|
||||||
|
sub.SendJSON(messages.Message{
|
||||||
|
Action: messages.ActionKick,
|
||||||
|
})
|
||||||
|
sub.authenticated = false
|
||||||
|
sub.Username = ""
|
||||||
|
|
||||||
|
removed++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If any changes to blocklists were made: send the Who List.
|
||||||
|
if removed > 0 {
|
||||||
|
s.SendWhoList()
|
||||||
|
}
|
||||||
|
|
||||||
|
enc.Encode(result{
|
||||||
|
OK: true,
|
||||||
|
Removed: removed,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// UserProfile (/api/profile) fetches profile information about a user.
|
// UserProfile (/api/profile) fetches profile information about a user.
|
||||||
//
|
//
|
||||||
// This endpoint will proxy to your WebhookURL for the "profile" endpoint.
|
// This endpoint will proxy to your WebhookURL for the "profile" endpoint.
|
||||||
|
|
|
@ -160,7 +160,7 @@ func (s *Server) KickCommand(words []string, sub *Subscriber) {
|
||||||
s.Broadcast(messages.Message{
|
s.Broadcast(messages.Message{
|
||||||
Action: messages.ActionPresence,
|
Action: messages.ActionPresence,
|
||||||
Username: username,
|
Username: username,
|
||||||
Message: "has been kicked from the room!",
|
Message: messages.PresenceKicked,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,7 +237,7 @@ func (s *Server) BanCommand(words []string, sub *Subscriber) {
|
||||||
s.Broadcast(messages.Message{
|
s.Broadcast(messages.Message{
|
||||||
Action: messages.ActionPresence,
|
Action: messages.ActionPresence,
|
||||||
Username: username,
|
Username: username,
|
||||||
Message: "has been banned!",
|
Message: messages.PresenceBanned,
|
||||||
})
|
})
|
||||||
|
|
||||||
other.ChatServer("You have been banned from the chat room by %s. You may come back after %d hours.", sub.Username, duration/time.Hour)
|
other.ChatServer("You have been banned from the chat room by %s. You may come back after %d hours.", sub.Username, duration/time.Hour)
|
||||||
|
|
|
@ -97,7 +97,7 @@ func (s *Server) OnLogin(sub *Subscriber, msg messages.Message) {
|
||||||
s.Broadcast(messages.Message{
|
s.Broadcast(messages.Message{
|
||||||
Action: messages.ActionPresence,
|
Action: messages.ActionPresence,
|
||||||
Username: msg.Username,
|
Username: msg.Username,
|
||||||
Message: "has joined the room!",
|
Message: messages.PresenceJoined,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Send the user back their settings.
|
// Send the user back their settings.
|
||||||
|
@ -379,14 +379,14 @@ func (s *Server) OnMe(sub *Subscriber, msg messages.Message) {
|
||||||
s.Broadcast(messages.Message{
|
s.Broadcast(messages.Message{
|
||||||
Action: messages.ActionPresence,
|
Action: messages.ActionPresence,
|
||||||
Username: sub.Username,
|
Username: sub.Username,
|
||||||
Message: "has exited the room!",
|
Message: messages.PresenceExited,
|
||||||
})
|
})
|
||||||
} else if sub.ChatStatus == "hidden" && msg.ChatStatus != "hidden" {
|
} else if sub.ChatStatus == "hidden" && msg.ChatStatus != "hidden" {
|
||||||
// Leaving hidden - fake join message
|
// Leaving hidden - fake join message
|
||||||
s.Broadcast(messages.Message{
|
s.Broadcast(messages.Message{
|
||||||
Action: messages.ActionPresence,
|
Action: messages.ActionPresence,
|
||||||
Username: sub.Username,
|
Username: sub.Username,
|
||||||
Message: "has joined the room!",
|
Message: messages.PresenceJoined,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else if msg.ChatStatus == "hidden" {
|
} else if msg.ChatStatus == "hidden" {
|
||||||
|
|
|
@ -131,3 +131,12 @@ const (
|
||||||
VideoFlagMutualOpen // viewer wants to auto-open viewers' cameras
|
VideoFlagMutualOpen // viewer wants to auto-open viewers' cameras
|
||||||
VideoFlagOnlyVIP // can only shows as active to VIP members
|
VideoFlagOnlyVIP // can only shows as active to VIP members
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Presence message templates.
|
||||||
|
const (
|
||||||
|
PresenceJoined = "has joined the room!"
|
||||||
|
PresenceExited = "has exited the room!"
|
||||||
|
PresenceKicked = "has been kicked from the room!"
|
||||||
|
PresenceBanned = "has been banned!"
|
||||||
|
PresenceTimedOut = "has timed out!"
|
||||||
|
)
|
||||||
|
|
|
@ -65,7 +65,7 @@ func (s *Server) KickIdlePollUsers() {
|
||||||
s.Broadcast(messages.Message{
|
s.Broadcast(messages.Message{
|
||||||
Action: messages.ActionPresence,
|
Action: messages.ActionPresence,
|
||||||
Username: sub.Username,
|
Username: sub.Username,
|
||||||
Message: "has timed out!",
|
Message: messages.PresenceTimedOut,
|
||||||
})
|
})
|
||||||
s.SendWhoList()
|
s.SendWhoList()
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ func (s *Server) Setup() error {
|
||||||
mux.Handle("/api/statistics", s.Statistics())
|
mux.Handle("/api/statistics", s.Statistics())
|
||||||
mux.Handle("/api/blocklist", s.BlockList())
|
mux.Handle("/api/blocklist", s.BlockList())
|
||||||
mux.Handle("/api/block/now", s.BlockNow())
|
mux.Handle("/api/block/now", s.BlockNow())
|
||||||
|
mux.Handle("/api/disconnect/now", s.DisconnectNow())
|
||||||
mux.Handle("/api/authenticate", s.Authenticate())
|
mux.Handle("/api/authenticate", s.Authenticate())
|
||||||
mux.Handle("/api/shutdown", s.ShutdownAPI())
|
mux.Handle("/api/shutdown", s.ShutdownAPI())
|
||||||
mux.Handle("/api/profile", s.UserProfile())
|
mux.Handle("/api/profile", s.UserProfile())
|
||||||
|
|
|
@ -99,7 +99,7 @@ func (s *Server) NewPollingSubscriber(ctx context.Context, cancelFunc func()) *S
|
||||||
s.Broadcast(messages.Message{
|
s.Broadcast(messages.Message{
|
||||||
Action: messages.ActionPresence,
|
Action: messages.ActionPresence,
|
||||||
Username: sub.Username,
|
Username: sub.Username,
|
||||||
Message: "has exited the room!",
|
Message: messages.PresenceExited,
|
||||||
})
|
})
|
||||||
s.SendWhoList()
|
s.SendWhoList()
|
||||||
}
|
}
|
||||||
|
@ -167,7 +167,7 @@ func (sub *Subscriber) ReadLoop(s *Server) {
|
||||||
s.Broadcast(messages.Message{
|
s.Broadcast(messages.Message{
|
||||||
Action: messages.ActionPresence,
|
Action: messages.ActionPresence,
|
||||||
Username: sub.Username,
|
Username: sub.Username,
|
||||||
Message: "has exited the room!",
|
Message: messages.PresenceExited,
|
||||||
})
|
})
|
||||||
s.SendWhoList()
|
s.SendWhoList()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user