64 changed files with 1568 additions and 936 deletions
@ -1,12 +0,0 @@ |
|||||||
github.com/gorilla/context 215affda49addc4c8ef7e2534915df2c8c35c6cd |
|
||||||
github.com/gorilla/mux ba336c9cfb43552c90de6cb2ceedd3271c747558 |
|
||||||
github.com/gorilla/securecookie aeade84400a85c6875264ae51c7a56ecdcb61751 |
|
||||||
github.com/gorilla/websocket 6eb6ad425a89d9da7a5549bc6da8f79ba5c17844 |
|
||||||
github.com/longsleep/pkac 0.0.1 |
|
||||||
github.com/satori/go.uuid afe1e2ddf0f05b7c29d388a3f8e76cb15c2231ca |
|
||||||
github.com/strukturag/goacceptlanguageparser goacceptlanguageparser_v100 |
|
||||||
github.com/strukturag/httputils httputils_v012 |
|
||||||
github.com/strukturag/phoenix phoenix_v100 |
|
||||||
github.com/strukturag/sloth v0.9.2 |
|
||||||
github.com/dlintw/goconf dcc070983490608a14480e3bf943bad464785df5 |
|
||||||
github.com/nats-io/nats v1.1.6 |
|
|
@ -0,0 +1,28 @@ |
|||||||
|
/* |
||||||
|
* Spreed WebRTC. |
||||||
|
* Copyright (C) 2013-2015 struktur AG |
||||||
|
* |
||||||
|
* This file is part of Spreed WebRTC. |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
package channelling |
||||||
|
|
||||||
|
type ChannellingAPI interface { |
||||||
|
OnConnect(*Client, *Session) (interface{}, error) |
||||||
|
OnDisconnect(*Client, *Session) |
||||||
|
OnIncoming(Sender, *Session, *DataIncoming) (interface{}, error) |
||||||
|
} |
@ -0,0 +1,185 @@ |
|||||||
|
/* |
||||||
|
* Spreed WebRTC. |
||||||
|
* Copyright (C) 2013-2015 struktur AG |
||||||
|
* |
||||||
|
* This file is part of Spreed WebRTC. |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
package api |
||||||
|
|
||||||
|
import ( |
||||||
|
"log" |
||||||
|
|
||||||
|
"github.com/strukturag/spreed-webrtc/go/channelling" |
||||||
|
) |
||||||
|
|
||||||
|
const ( |
||||||
|
maxConferenceSize = 100 |
||||||
|
apiVersion = 1.4 // Keep this in sync with CHANNELING-API docs.Hand
|
||||||
|
) |
||||||
|
|
||||||
|
type channellingAPI struct { |
||||||
|
RoomStatusManager channelling.RoomStatusManager |
||||||
|
SessionEncoder channelling.SessionEncoder |
||||||
|
SessionManager channelling.SessionManager |
||||||
|
StatsCounter channelling.StatsCounter |
||||||
|
ContactManager channelling.ContactManager |
||||||
|
TurnDataCreator channelling.TurnDataCreator |
||||||
|
Unicaster channelling.Unicaster |
||||||
|
BusManager channelling.BusManager |
||||||
|
config *channelling.Config |
||||||
|
} |
||||||
|
|
||||||
|
// New creates and initializes a new ChannellingAPI using
|
||||||
|
// various other services for initialization. It is intended to handle
|
||||||
|
// incoming and outgoing channeling API events from clients.
|
||||||
|
func New(config *channelling.Config, |
||||||
|
roomStatus channelling.RoomStatusManager, |
||||||
|
sessionEncoder channelling.SessionEncoder, |
||||||
|
sessionManager channelling.SessionManager, |
||||||
|
statsCounter channelling.StatsCounter, |
||||||
|
contactManager channelling.ContactManager, |
||||||
|
turnDataCreator channelling.TurnDataCreator, |
||||||
|
unicaster channelling.Unicaster, |
||||||
|
busManager channelling.BusManager) channelling.ChannellingAPI { |
||||||
|
return &channellingAPI{ |
||||||
|
roomStatus, |
||||||
|
sessionEncoder, |
||||||
|
sessionManager, |
||||||
|
statsCounter, |
||||||
|
contactManager, |
||||||
|
turnDataCreator, |
||||||
|
unicaster, |
||||||
|
busManager, |
||||||
|
config, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func (api *channellingAPI) OnConnect(client *channelling.Client, session *channelling.Session) (interface{}, error) { |
||||||
|
api.Unicaster.OnConnect(client, session) |
||||||
|
self, err := api.HandleSelf(session) |
||||||
|
if err == nil { |
||||||
|
api.BusManager.Trigger(channelling.BusManagerConnect, session.Id, "", nil) |
||||||
|
} |
||||||
|
return self, err |
||||||
|
} |
||||||
|
|
||||||
|
func (api *channellingAPI) OnDisconnect(client *channelling.Client, session *channelling.Session) { |
||||||
|
api.Unicaster.OnDisconnect(client, session) |
||||||
|
api.BusManager.Trigger(channelling.BusManagerDisconnect, session.Id, "", nil) |
||||||
|
} |
||||||
|
|
||||||
|
func (api *channellingAPI) OnIncoming(sender channelling.Sender, session *channelling.Session, msg *channelling.DataIncoming) (interface{}, error) { |
||||||
|
switch msg.Type { |
||||||
|
case "Self": |
||||||
|
return api.HandleSelf(session) |
||||||
|
case "Hello": |
||||||
|
if msg.Hello == nil { |
||||||
|
return nil, channelling.NewDataError("bad_request", "message did not contain Hello") |
||||||
|
} |
||||||
|
|
||||||
|
return api.HandleHello(session, msg.Hello, sender) |
||||||
|
case "Offer": |
||||||
|
if msg.Offer == nil || msg.Offer.Offer == nil { |
||||||
|
log.Println("Received invalid offer message.", msg) |
||||||
|
break |
||||||
|
} |
||||||
|
if _, ok := msg.Offer.Offer["_token"]; !ok { |
||||||
|
// Trigger offer event when offer has no token, so this is
|
||||||
|
// not triggered for peerxfer and peerscreenshare offers.
|
||||||
|
api.BusManager.Trigger(channelling.BusManagerOffer, session.Id, msg.Offer.To, nil) |
||||||
|
} |
||||||
|
|
||||||
|
session.Unicast(msg.Offer.To, msg.Offer) |
||||||
|
case "Candidate": |
||||||
|
if msg.Candidate == nil || msg.Candidate.Candidate == nil { |
||||||
|
log.Println("Received invalid candidate message.", msg) |
||||||
|
break |
||||||
|
} |
||||||
|
|
||||||
|
session.Unicast(msg.Candidate.To, msg.Candidate) |
||||||
|
case "Answer": |
||||||
|
if msg.Answer == nil || msg.Answer.Answer == nil { |
||||||
|
log.Println("Received invalid answer message.", msg) |
||||||
|
break |
||||||
|
} |
||||||
|
if _, ok := msg.Answer.Answer["_token"]; !ok { |
||||||
|
// Trigger answer event when answer has no token. so this is
|
||||||
|
// not triggered for peerxfer and peerscreenshare answers.
|
||||||
|
api.BusManager.Trigger(channelling.BusManagerAnswer, session.Id, msg.Answer.To, nil) |
||||||
|
} |
||||||
|
|
||||||
|
session.Unicast(msg.Answer.To, msg.Answer) |
||||||
|
case "Users": |
||||||
|
return api.HandleUsers(session) |
||||||
|
case "Authentication": |
||||||
|
if msg.Authentication == nil || msg.Authentication.Authentication == nil { |
||||||
|
return nil, channelling.NewDataError("bad_request", "message did not contain Authentication") |
||||||
|
} |
||||||
|
|
||||||
|
return api.HandleAuthentication(session, msg.Authentication.Authentication) |
||||||
|
case "Bye": |
||||||
|
if msg.Bye == nil { |
||||||
|
log.Println("Received invalid bye message.", msg) |
||||||
|
break |
||||||
|
} |
||||||
|
api.BusManager.Trigger(channelling.BusManagerBye, session.Id, msg.Bye.To, nil) |
||||||
|
|
||||||
|
session.Unicast(msg.Bye.To, msg.Bye) |
||||||
|
case "Status": |
||||||
|
if msg.Status == nil { |
||||||
|
log.Println("Received invalid status message.", msg) |
||||||
|
break |
||||||
|
} |
||||||
|
|
||||||
|
//log.Println("Status", msg.Status)
|
||||||
|
session.Update(&channelling.SessionUpdate{Types: []string{"Status"}, Status: msg.Status.Status}) |
||||||
|
session.BroadcastStatus() |
||||||
|
case "Chat": |
||||||
|
if msg.Chat == nil || msg.Chat.Chat == nil { |
||||||
|
log.Println("Received invalid chat message.", msg) |
||||||
|
break |
||||||
|
} |
||||||
|
|
||||||
|
api.HandleChat(session, msg.Chat) |
||||||
|
case "Conference": |
||||||
|
if msg.Conference == nil { |
||||||
|
log.Println("Received invalid conference message.", msg) |
||||||
|
break |
||||||
|
} |
||||||
|
|
||||||
|
api.HandleConference(session, msg.Conference) |
||||||
|
case "Alive": |
||||||
|
return msg.Alive, nil |
||||||
|
case "Sessions": |
||||||
|
if msg.Sessions == nil || msg.Sessions.Sessions == nil { |
||||||
|
return nil, channelling.NewDataError("bad_request", "message did not contain Sessions") |
||||||
|
} |
||||||
|
|
||||||
|
return api.HandleSessions(session, msg.Sessions.Sessions) |
||||||
|
case "Room": |
||||||
|
if msg.Room == nil { |
||||||
|
return nil, channelling.NewDataError("bad_request", "message did not contain Room") |
||||||
|
} |
||||||
|
|
||||||
|
return api.HandleRoom(session, msg.Room) |
||||||
|
default: |
||||||
|
log.Println("OnText unhandled message type", msg.Type) |
||||||
|
} |
||||||
|
|
||||||
|
return nil, nil |
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
/* |
||||||
|
* Spreed WebRTC. |
||||||
|
* Copyright (C) 2013-2015 struktur AG |
||||||
|
* |
||||||
|
* This file is part of Spreed WebRTC. |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
package api |
||||||
|
|
||||||
|
import ( |
||||||
|
"log" |
||||||
|
|
||||||
|
"github.com/strukturag/spreed-webrtc/go/channelling" |
||||||
|
) |
||||||
|
|
||||||
|
func (api *channellingAPI) HandleAuthentication(session *channelling.Session, st *channelling.SessionToken) (*channelling.DataSelf, error) { |
||||||
|
if err := api.SessionManager.Authenticate(session, st, ""); err != nil { |
||||||
|
log.Println("Authentication failed", err, st.Userid, st.Nonce) |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
log.Println("Authentication success", session.Userid()) |
||||||
|
self, err := api.HandleSelf(session) |
||||||
|
if err == nil { |
||||||
|
session.BroadcastStatus() |
||||||
|
} |
||||||
|
|
||||||
|
return self, err |
||||||
|
} |
@ -0,0 +1,68 @@ |
|||||||
|
/* |
||||||
|
* Spreed WebRTC. |
||||||
|
* Copyright (C) 2013-2015 struktur AG |
||||||
|
* |
||||||
|
* This file is part of Spreed WebRTC. |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
package api |
||||||
|
|
||||||
|
import ( |
||||||
|
"log" |
||||||
|
"time" |
||||||
|
|
||||||
|
"github.com/strukturag/spreed-webrtc/go/channelling" |
||||||
|
) |
||||||
|
|
||||||
|
func (api *channellingAPI) HandleChat(session *channelling.Session, chat *channelling.DataChat) { |
||||||
|
// TODO(longsleep): Limit sent chat messages per incoming connection.
|
||||||
|
msg := chat.Chat |
||||||
|
to := chat.To |
||||||
|
|
||||||
|
if !msg.NoEcho { |
||||||
|
session.Unicast(session.Id, chat) |
||||||
|
} |
||||||
|
msg.Time = time.Now().Format(time.RFC3339) |
||||||
|
if to == "" { |
||||||
|
// TODO(longsleep): Check if chat broadcast is allowed.
|
||||||
|
if session.Hello { |
||||||
|
api.StatsCounter.CountBroadcastChat() |
||||||
|
session.Broadcast(chat) |
||||||
|
} |
||||||
|
} else { |
||||||
|
if msg.Status != nil { |
||||||
|
if msg.Status.ContactRequest != nil { |
||||||
|
if !api.config.WithModule("contacts") { |
||||||
|
return |
||||||
|
} |
||||||
|
if err := api.ContactManager.ContactrequestHandler(session, to, msg.Status.ContactRequest); err != nil { |
||||||
|
log.Println("Ignoring invalid contact request.", err) |
||||||
|
return |
||||||
|
} |
||||||
|
msg.Status.ContactRequest.Userid = session.Userid() |
||||||
|
} |
||||||
|
} else { |
||||||
|
api.StatsCounter.CountUnicastChat() |
||||||
|
} |
||||||
|
|
||||||
|
session.Unicast(to, chat) |
||||||
|
if msg.Mid != "" { |
||||||
|
// Send out delivery confirmation status chat message.
|
||||||
|
session.Unicast(session.Id, &channelling.DataChat{To: to, Type: "Chat", Chat: &channelling.DataChatMessage{Mid: msg.Mid, Status: &channelling.DataChatStatus{State: "sent"}}}) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
/* |
||||||
|
* Spreed WebRTC. |
||||||
|
* Copyright (C) 2013-2015 struktur AG |
||||||
|
* |
||||||
|
* This file is part of Spreed WebRTC. |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
package api |
||||||
|
|
||||||
|
import ( |
||||||
|
"log" |
||||||
|
|
||||||
|
"github.com/strukturag/spreed-webrtc/go/channelling" |
||||||
|
) |
||||||
|
|
||||||
|
func (api *channellingAPI) HandleConference(session *channelling.Session, conference *channelling.DataConference) { |
||||||
|
// Check conference maximum size.
|
||||||
|
if len(conference.Conference) > maxConferenceSize { |
||||||
|
log.Println("Refusing to create conference above limit.", len(conference.Conference)) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
// Send conference update to anyone.
|
||||||
|
for _, id := range conference.Conference { |
||||||
|
if id != session.Id { |
||||||
|
session.Unicast(id, conference) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,48 @@ |
|||||||
|
/* |
||||||
|
* Spreed WebRTC. |
||||||
|
* Copyright (C) 2013-2015 struktur AG |
||||||
|
* |
||||||
|
* This file is part of Spreed WebRTC. |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
package api |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/strukturag/spreed-webrtc/go/channelling" |
||||||
|
) |
||||||
|
|
||||||
|
func (api *channellingAPI) HandleHello(session *channelling.Session, hello *channelling.DataHello, sender channelling.Sender) (*channelling.DataWelcome, error) { |
||||||
|
// TODO(longsleep): Filter room id and user agent.
|
||||||
|
session.Update(&channelling.SessionUpdate{Types: []string{"Ua"}, Ua: hello.Ua}) |
||||||
|
|
||||||
|
// Compatibily for old clients.
|
||||||
|
roomName := hello.Name |
||||||
|
if roomName == "" { |
||||||
|
roomName = hello.Id |
||||||
|
} |
||||||
|
|
||||||
|
room, err := session.JoinRoom(roomName, hello.Type, hello.Credentials, sender) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
return &channelling.DataWelcome{ |
||||||
|
Type: "Welcome", |
||||||
|
Room: room, |
||||||
|
Users: api.RoomStatusManager.RoomUsers(session), |
||||||
|
}, nil |
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
/* |
||||||
|
* Spreed WebRTC. |
||||||
|
* Copyright (C) 2013-2015 struktur AG |
||||||
|
* |
||||||
|
* This file is part of Spreed WebRTC. |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
package api |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/strukturag/spreed-webrtc/go/channelling" |
||||||
|
) |
||||||
|
|
||||||
|
func (api *channellingAPI) HandleRoom(session *channelling.Session, room *channelling.DataRoom) (*channelling.DataRoom, error) { |
||||||
|
room, err := api.RoomStatusManager.UpdateRoom(session, room) |
||||||
|
if err == nil { |
||||||
|
session.Broadcast(room) |
||||||
|
} |
||||||
|
|
||||||
|
return room, err |
||||||
|
} |
@ -0,0 +1,53 @@ |
|||||||
|
/* |
||||||
|
* Spreed WebRTC. |
||||||
|
* Copyright (C) 2013-2015 struktur AG |
||||||
|
* |
||||||
|
* This file is part of Spreed WebRTC. |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
package api |
||||||
|
|
||||||
|
import ( |
||||||
|
"log" |
||||||
|
|
||||||
|
"github.com/strukturag/spreed-webrtc/go/channelling" |
||||||
|
) |
||||||
|
|
||||||
|
func (api *channellingAPI) HandleSelf(session *channelling.Session) (*channelling.DataSelf, error) { |
||||||
|
token, err := api.SessionEncoder.EncodeSessionToken(session) |
||||||
|
if err != nil { |
||||||
|
log.Println("Error in OnRegister", err) |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
log.Println("Created new session token", len(token), token) |
||||||
|
self := &channelling.DataSelf{ |
||||||
|
Type: "Self", |
||||||
|
Id: session.Id, |
||||||
|
Sid: session.Sid, |
||||||
|
Userid: session.Userid(), |
||||||
|
Suserid: api.SessionEncoder.EncodeSessionUserID(session), |
||||||
|
Token: token, |
||||||
|
Version: api.config.Version, |
||||||
|
ApiVersion: apiVersion, |
||||||
|
Turn: api.TurnDataCreator.CreateTurnData(session), |
||||||
|
Stun: api.config.StunURIs, |
||||||
|
} |
||||||
|
api.BusManager.Trigger(channelling.BusManagerSession, session.Id, session.Userid(), nil) |
||||||
|
|
||||||
|
return self, nil |
||||||
|
} |
@ -0,0 +1,60 @@ |
|||||||
|
/* |
||||||
|
* Spreed WebRTC. |
||||||
|
* Copyright (C) 2013-2015 struktur AG |
||||||
|
* |
||||||
|
* This file is part of Spreed WebRTC. |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
package api |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/strukturag/spreed-webrtc/go/channelling" |
||||||
|
) |
||||||
|
|
||||||
|
func (api *channellingAPI) HandleSessions(session *channelling.Session, sessions *channelling.DataSessionsRequest) (*channelling.DataSessions, error) { |
||||||
|
switch sessions.Type { |
||||||
|
case "contact": |
||||||
|
if !api.config.WithModule("contacts") { |
||||||
|
return nil, channelling.NewDataError("contacts_not_enabled", "incoming contacts session request with contacts disabled") |
||||||
|
} |
||||||
|
userID, err := api.ContactManager.GetContactID(session, sessions.Token) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
return &channelling.DataSessions{ |
||||||
|
Type: "Sessions", |
||||||
|
Users: api.SessionManager.GetUserSessions(session, userID), |
||||||
|
Sessions: sessions, |
||||||
|
}, nil |
||||||
|
case "session": |
||||||
|
id, err := session.DecodeAttestation(sessions.Token) |
||||||
|
if err != nil { |
||||||
|
return nil, channelling.NewDataError("bad_attestation", err.Error()) |
||||||
|
} |
||||||
|
session, ok := api.Unicaster.GetSession(id) |
||||||
|
if !ok { |
||||||
|
return nil, channelling.NewDataError("no_such_session", "cannot retrieve session") |
||||||
|
} |
||||||
|
return &channelling.DataSessions{ |
||||||
|
Type: "Sessions", |
||||||
|
Users: []*channelling.DataSession{session.Data()}, |
||||||
|
Sessions: sessions, |
||||||
|
}, nil |
||||||
|
default: |
||||||
|
return nil, channelling.NewDataError("bad_request", "unknown sessions request type") |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,36 @@ |
|||||||
|
/* |
||||||
|
* Spreed WebRTC. |
||||||
|
* Copyright (C) 2013-2015 struktur AG |
||||||
|
* |
||||||
|
* This file is part of Spreed WebRTC. |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
package api |
||||||
|
|
||||||
|
import ( |
||||||
|
"github.com/strukturag/spreed-webrtc/go/channelling" |
||||||
|
) |
||||||
|
|
||||||
|
func (api *channellingAPI) HandleUsers(session *channelling.Session) (sessions *channelling.DataSessions, err error) { |
||||||
|
if session.Hello { |
||||||
|
sessions = &channelling.DataSessions{Type: "Users", Users: api.RoomStatusManager.RoomUsers(session)} |
||||||
|
} else { |
||||||
|
err = channelling.NewDataError("not_in_room", "Cannot list users without a current room") |
||||||
|
} |
||||||
|
|
||||||
|
return |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
/* |
||||||
|
* Spreed WebRTC. |
||||||
|
* Copyright (C) 2013-2015 struktur AG |
||||||
|
* |
||||||
|
* This file is part of Spreed WebRTC. |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
package channelling |
||||||
|
|
||||||
|
type ClientStats interface { |
||||||
|
ClientInfo(details bool) (int, map[string]*DataSession, map[string]string) |
||||||
|
} |
@ -0,0 +1,43 @@ |
|||||||
|
package channelling |
||||||
|
|
||||||
|
import ( |
||||||
|
"net/http" |
||||||
|
) |
||||||
|
|
||||||
|
type Config struct { |
||||||
|
Title string // Title
|
||||||
|
Ver string `json:"-"` // Version (not exported to Javascript)
|
||||||
|
S string // Static URL prefix with version
|
||||||
|
B string // Base URL
|
||||||
|
Token string // Server token
|
||||||
|
Renegotiation bool // Renegotiation flag
|
||||||
|
StunURIs []string // STUN server URIs
|
||||||
|
TurnURIs []string // TURN server URIs
|
||||||
|
Tokens bool // True when we got a tokens file
|
||||||
|
Version string // Server version number
|
||||||
|
UsersEnabled bool // Flag if users are enabled
|
||||||
|
UsersAllowRegistration bool // Flag if users can register
|
||||||
|
UsersMode string // Users mode string
|
||||||
|
DefaultRoomEnabled bool // Flag if default room ("") is enabled
|
||||||
|
Plugin string // Plugin to load
|
||||||
|
AuthorizeRoomCreation bool // Whether a user account is required to create rooms
|
||||||
|
AuthorizeRoomJoin bool // Whether a user account is required to join rooms
|
||||||
|
Modules []string // List of enabled modules
|
||||||
|
ModulesTable map[string]bool `json:"-"` // Map of enabled modules
|
||||||
|
GlobalRoomID string `json:"-"` // Id of the global room (not exported to Javascript)
|
||||||
|
ContentSecurityPolicy string `json:"-"` // HTML content security policy
|
||||||
|
ContentSecurityPolicyReportOnly string `json:"-"` // HTML content security policy in report only mode
|
||||||
|
RoomTypeDefault string `json:"-"` // New rooms default to this type
|
||||||
|
} |
||||||
|
|
||||||
|
func (config *Config) WithModule(m string) bool { |
||||||
|
if val, ok := config.ModulesTable[m]; ok && val { |
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
func (config *Config) Get(request *http.Request) (int, interface{}, http.Header) { |
||||||
|
return 200, config, http.Header{"Content-Type": {"application/json; charset=utf-8"}} |
||||||
|
} |
@ -0,0 +1,27 @@ |
|||||||
|
/* |
||||||
|
* Spreed WebRTC. |
||||||
|
* Copyright (C) 2013-2015 struktur AG |
||||||
|
* |
||||||
|
* This file is part of Spreed WebRTC. |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
package channelling |
||||||
|
|
||||||
|
type ContactManager interface { |
||||||
|
ContactrequestHandler(*Session, string, *DataContactRequest) error |
||||||
|
GetContactID(*Session, string) (string, error) |
||||||
|
} |
@ -1,4 +1,4 @@ |
|||||||
package main |
package channelling |
||||||
|
|
||||||
import ( |
import ( |
||||||
"errors" |
"errors" |
@ -0,0 +1,60 @@ |
|||||||
|
/* |
||||||
|
* Spreed WebRTC. |
||||||
|
* Copyright (C) 2013-2015 struktur AG |
||||||
|
* |
||||||
|
* This file is part of Spreed WebRTC. |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
package channelling |
||||||
|
|
||||||
|
import ( |
||||||
|
"time" |
||||||
|
) |
||||||
|
|
||||||
|
type SessionAttestation struct { |
||||||
|
refresh int64 |
||||||
|
token string |
||||||
|
s *Session |
||||||
|
} |
||||||
|
|
||||||
|
func (sa *SessionAttestation) Update() (string, error) { |
||||||
|
token, err := sa.Encode() |
||||||
|
if err == nil { |
||||||
|
sa.token = token |
||||||
|
sa.refresh = time.Now().Unix() + 180 // expires after 3 minutes
|
||||||
|
} |
||||||
|
return token, err |
||||||
|
} |
||||||
|
|
||||||
|
func (sa *SessionAttestation) Token() (token string) { |
||||||
|
if sa.refresh < time.Now().Unix() { |
||||||
|
token, _ = sa.Update() |
||||||
|
} else { |
||||||
|
token = sa.token |
||||||
|
} |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
func (sa *SessionAttestation) Encode() (string, error) { |
||||||
|
return sa.s.attestations.Encode("attestation", sa.s.Id) |
||||||
|
} |
||||||
|
|
||||||
|
func (sa *SessionAttestation) Decode(token string) (string, error) { |
||||||
|
var id string |
||||||
|
err := sa.s.attestations.Decode("attestation", token, &id) |
||||||
|
return id, err |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
/* |
||||||
|
* Spreed WebRTC. |
||||||
|
* Copyright (C) 2013-2015 struktur AG |
||||||
|
* |
||||||
|
* This file is part of Spreed WebRTC. |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
package channelling |
||||||
|
|
||||||
|
type SessionStore interface { |
||||||
|
GetSession(id string) (session *Session, ok bool) |
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
/* |
||||||
|
* Spreed WebRTC. |
||||||
|
* Copyright (C) 2013-2015 struktur AG |
||||||
|
* |
||||||
|
* This file is part of Spreed WebRTC. |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
package channelling |
||||||
|
|
||||||
|
type SessionToken struct { |
||||||
|
Id string // Public session id.
|
||||||
|
Sid string // Secret session id.
|
||||||
|
Userid string // Public user id.
|
||||||
|
Nonce string `json:"Nonce,omitempty"` // User autentication nonce.
|
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
/* |
||||||
|
* Spreed WebRTC. |
||||||
|
* Copyright (C) 2013-2015 struktur AG |
||||||
|
* |
||||||
|
* This file is part of Spreed WebRTC. |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
package channelling |
||||||
|
|
||||||
|
type SessionUpdate struct { |
||||||
|
Types []string |
||||||
|
Ua string |
||||||
|
Prio int |
||||||
|
Status interface{} |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
/* |
||||||
|
* Spreed WebRTC. |
||||||
|
* Copyright (C) 2013-2015 struktur AG |
||||||
|
* |
||||||
|
* This file is part of Spreed WebRTC. |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
package channelling |
||||||
|
|
||||||
|
type TurnDataCreator interface { |
||||||
|
CreateTurnData(*Session) *DataTurn |
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
/* |
||||||
|
* Spreed WebRTC. |
||||||
|
* Copyright (C) 2013-2015 struktur AG |
||||||
|
* |
||||||
|
* This file is part of Spreed WebRTC. |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
package channelling |
||||||
|
|
||||||
|
type Unicaster interface { |
||||||
|
SessionStore |
||||||
|
OnConnect(*Client, *Session) |
||||||
|
OnDisconnect(*Client, *Session) |
||||||
|
Unicast(to string, outgoing *DataOutgoing) |
||||||
|
} |
@ -1,348 +0,0 @@ |
|||||||
/* |
|
||||||
* Spreed WebRTC. |
|
||||||
* Copyright (C) 2013-2015 struktur AG |
|
||||||
* |
|
||||||
* This file is part of Spreed WebRTC. |
|
||||||
* |
|
||||||
* This program is free software: you can redistribute it and/or modify |
|
||||||
* it under the terms of the GNU Affero General Public License as published by |
|
||||||
* the Free Software Foundation, either version 3 of the License, or |
|
||||||
* (at your option) any later version. |
|
||||||
* |
|
||||||
* This program is distributed in the hope that it will be useful, |
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||||
* GNU Affero General Public License for more details. |
|
||||||
* |
|
||||||
* You should have received a copy of the GNU Affero General Public License |
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
* |
|
||||||
*/ |
|
||||||
|
|
||||||
package main |
|
||||||
|
|
||||||
import ( |
|
||||||
"log" |
|
||||||
"time" |
|
||||||
) |
|
||||||
|
|
||||||
const ( |
|
||||||
maxConferenceSize = 100 |
|
||||||
apiVersion = 1.4 // Keep this in sync with CHANNELING-API docs.Hand
|
|
||||||
) |
|
||||||
|
|
||||||
type ChannellingAPI interface { |
|
||||||
OnConnect(Client, *Session) (interface{}, error) |
|
||||||
OnDisconnect(Client, *Session) |
|
||||||
OnIncoming(Sender, *Session, *DataIncoming) (interface{}, error) |
|
||||||
} |
|
||||||
|
|
||||||
type channellingAPI struct { |
|
||||||
*Config |
|
||||||
RoomStatusManager |
|
||||||
SessionEncoder |
|
||||||
SessionManager |
|
||||||
StatsCounter |
|
||||||
ContactManager |
|
||||||
TurnDataCreator |
|
||||||
Unicaster |
|
||||||
BusManager |
|
||||||
} |
|
||||||
|
|
||||||
// NewChannellingAPI creates and initializes a new ChannellingAPI using
|
|
||||||
// various other services for initialization. It is intended to handle
|
|
||||||
// incoming and outgoing channeling API events from clients.
|
|
||||||
func NewChannellingAPI(config *Config, roomStatus RoomStatusManager, sessionEncoder SessionEncoder, sessionManager SessionManager, statsCounter StatsCounter, contactManager ContactManager, turnDataCreator TurnDataCreator, unicaster Unicaster, busManager BusManager) ChannellingAPI { |
|
||||||
return &channellingAPI{ |
|
||||||
config, |
|
||||||
roomStatus, |
|
||||||
sessionEncoder, |
|
||||||
sessionManager, |
|
||||||
statsCounter, |
|
||||||
contactManager, |
|
||||||
turnDataCreator, |
|
||||||
unicaster, |
|
||||||
busManager, |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
func (api *channellingAPI) OnConnect(client Client, session *Session) (interface{}, error) { |
|
||||||
api.Unicaster.OnConnect(client, session) |
|
||||||
self, err := api.HandleSelf(session) |
|
||||||
if err == nil { |
|
||||||
api.Trigger(BusManagerConnect, session.Id, "", nil) |
|
||||||
} |
|
||||||
return self, err |
|
||||||
} |
|
||||||
|
|
||||||
func (api *channellingAPI) OnDisconnect(client Client, session *Session) { |
|
||||||
api.Unicaster.OnDisconnect(client, session) |
|
||||||
api.Trigger(BusManagerDisconnect, session.Id, "", nil) |
|
||||||
} |
|
||||||
|
|
||||||
func (api *channellingAPI) OnIncoming(sender Sender, session *Session, msg *DataIncoming) (interface{}, error) { |
|
||||||
switch msg.Type { |
|
||||||
case "Self": |
|
||||||
return api.HandleSelf(session) |
|
||||||
case "Hello": |
|
||||||
if msg.Hello == nil { |
|
||||||
return nil, NewDataError("bad_request", "message did not contain Hello") |
|
||||||
} |
|
||||||
|
|
||||||
return api.HandleHello(session, msg.Hello, sender) |
|
||||||
case "Offer": |
|
||||||
if msg.Offer == nil || msg.Offer.Offer == nil { |
|
||||||
log.Println("Received invalid offer message.", msg) |
|
||||||
break |
|
||||||
} |
|
||||||
if _, ok := msg.Offer.Offer["_token"]; !ok { |
|
||||||
// Trigger offer event when offer has no token, so this is
|
|
||||||
// not triggered for peerxfer and peerscreenshare offers.
|
|
||||||
api.Trigger(BusManagerOffer, session.Id, msg.Offer.To, nil) |
|
||||||
} |
|
||||||
|
|
||||||
session.Unicast(msg.Offer.To, msg.Offer) |
|
||||||
case "Candidate": |
|
||||||
if msg.Candidate == nil || msg.Candidate.Candidate == nil { |
|
||||||
log.Println("Received invalid candidate message.", msg) |
|
||||||
break |
|
||||||
} |
|
||||||
|
|
||||||
session.Unicast(msg.Candidate.To, msg.Candidate) |
|
||||||
case "Answer": |
|
||||||
if msg.Answer == nil || msg.Answer.Answer == nil { |
|
||||||
log.Println("Received invalid answer message.", msg) |
|
||||||
break |
|
||||||
} |
|
||||||
if _, ok := msg.Answer.Answer["_token"]; !ok { |
|
||||||
// Trigger answer event when answer has no token. so this is
|
|
||||||
// not triggered for peerxfer and peerscreenshare answers.
|
|
||||||
api.Trigger(BusManagerAnswer, session.Id, msg.Answer.To, nil) |
|
||||||
} |
|
||||||
|
|
||||||
session.Unicast(msg.Answer.To, msg.Answer) |
|
||||||
case "Users": |
|
||||||
return api.HandleUsers(session) |
|
||||||
case "Authentication": |
|
||||||
if msg.Authentication == nil || msg.Authentication.Authentication == nil { |
|
||||||
return nil, NewDataError("bad_request", "message did not contain Authentication") |
|
||||||
} |
|
||||||
|
|
||||||
return api.HandleAuthentication(session, msg.Authentication.Authentication) |
|
||||||
case "Bye": |
|
||||||
if msg.Bye == nil { |
|
||||||
log.Println("Received invalid bye message.", msg) |
|
||||||
break |
|
||||||
} |
|
||||||
api.Trigger(BusManagerBye, session.Id, msg.Bye.To, nil) |
|
||||||
|
|
||||||
session.Unicast(msg.Bye.To, msg.Bye) |
|
||||||
case "Status": |
|
||||||
if msg.Status == nil { |
|
||||||
log.Println("Received invalid status message.", msg) |
|
||||||
break |
|
||||||
} |
|
||||||
|
|
||||||
//log.Println("Status", msg.Status)
|
|
||||||
session.Update(&SessionUpdate{Types: []string{"Status"}, Status: msg.Status.Status}) |
|
||||||
session.BroadcastStatus() |
|
||||||
case "Chat": |
|
||||||
if msg.Chat == nil || msg.Chat.Chat == nil { |
|
||||||
log.Println("Received invalid chat message.", msg) |
|
||||||
break |
|
||||||
} |
|
||||||
|
|
||||||
api.HandleChat(session, msg.Chat) |
|
||||||
case "Conference": |
|
||||||
if msg.Conference == nil { |
|
||||||
log.Println("Received invalid conference message.", msg) |
|
||||||
break |
|
||||||
} |
|
||||||
|
|
||||||
api.HandleConference(session, msg.Conference) |
|
||||||
case "Alive": |
|
||||||
return msg.Alive, nil |
|
||||||
case "Sessions": |
|
||||||
if msg.Sessions == nil || msg.Sessions.Sessions == nil { |
|
||||||
return nil, NewDataError("bad_request", "message did not contain Sessions") |
|
||||||
} |
|
||||||
|
|
||||||
return api.HandleSessions(session, msg.Sessions.Sessions) |
|
||||||
case "Room": |
|
||||||
if msg.Room == nil { |
|
||||||
return nil, NewDataError("bad_request", "message did not contain Room") |
|
||||||
} |
|
||||||
|
|
||||||
return api.HandleRoom(session, msg.Room) |
|
||||||
default: |
|
||||||
log.Println("OnText unhandled message type", msg.Type) |
|
||||||
} |
|
||||||
|
|
||||||
return nil, nil |
|
||||||
} |
|
||||||
|
|
||||||
func (api *channellingAPI) HandleSelf(session *Session) (*DataSelf, error) { |
|
||||||
token, err := api.EncodeSessionToken(session) |
|
||||||
if err != nil { |
|
||||||
log.Println("Error in OnRegister", err) |
|
||||||
return nil, err |
|
||||||
} |
|
||||||
|
|
||||||
log.Println("Created new session token", len(token), token) |
|
||||||
self := &DataSelf{ |
|
||||||
Type: "Self", |
|
||||||
Id: session.Id, |
|
||||||
Sid: session.Sid, |
|
||||||
Userid: session.Userid(), |
|
||||||
Suserid: api.EncodeSessionUserID(session), |
|
||||||
Token: token, |
|
||||||
Version: api.Version, |
|
||||||
ApiVersion: apiVersion, |
|
||||||
Turn: api.CreateTurnData(session), |
|
||||||
Stun: api.StunURIs, |
|
||||||
} |
|
||||||
api.Trigger(BusManagerSession, session.Id, session.Userid(), nil) |
|
||||||
|
|
||||||
return self, nil |
|
||||||
} |
|
||||||
|
|
||||||
func (api *channellingAPI) HandleHello(session *Session, hello *DataHello, sender Sender) (*DataWelcome, error) { |
|
||||||
// TODO(longsleep): Filter room id and user agent.
|
|
||||||
session.Update(&SessionUpdate{Types: []string{"Ua"}, Ua: hello.Ua}) |
|
||||||
|
|
||||||
// Compatibily for old clients.
|
|
||||||
roomName := hello.Name |
|
||||||
if roomName == "" { |
|
||||||
roomName = hello.Id |
|
||||||
} |
|
||||||
|
|
||||||
room, err := session.JoinRoom(roomName, hello.Type, hello.Credentials, sender) |
|
||||||
if err != nil { |
|
||||||
return nil, err |
|
||||||
} |
|
||||||
return &DataWelcome{ |
|
||||||
Type: "Welcome", |
|
||||||
Room: room, |
|
||||||
Users: api.RoomUsers(session), |
|
||||||
}, nil |
|
||||||
} |
|
||||||
|
|
||||||
func (api *channellingAPI) HandleUsers(session *Session) (sessions *DataSessions, err error) { |
|
||||||
if session.Hello { |
|
||||||
sessions = &DataSessions{Type: "Users", Users: api.RoomUsers(session)} |
|
||||||
} else { |
|
||||||
err = NewDataError("not_in_room", "Cannot list users without a current room") |
|
||||||
} |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
func (api *channellingAPI) HandleAuthentication(session *Session, st *SessionToken) (*DataSelf, error) { |
|
||||||
if err := api.Authenticate(session, st, ""); err != nil { |
|
||||||
log.Println("Authentication failed", err, st.Userid, st.Nonce) |
|
||||||
return nil, err |
|
||||||
} |
|
||||||
|
|
||||||
log.Println("Authentication success", session.Userid()) |
|
||||||
self, err := api.HandleSelf(session) |
|
||||||
if err == nil { |
|
||||||
session.BroadcastStatus() |
|
||||||
} |
|
||||||
|
|
||||||
return self, err |
|
||||||
} |
|
||||||
|
|
||||||
func (api *channellingAPI) HandleChat(session *Session, chat *DataChat) { |
|
||||||
// TODO(longsleep): Limit sent chat messages per incoming connection.
|
|
||||||
msg := chat.Chat |
|
||||||
to := chat.To |
|
||||||
|
|
||||||
if !msg.NoEcho { |
|
||||||
session.Unicast(session.Id, chat) |
|
||||||
} |
|
||||||
msg.Time = time.Now().Format(time.RFC3339) |
|
||||||
if to == "" { |
|
||||||
// TODO(longsleep): Check if chat broadcast is allowed.
|
|
||||||
if session.Hello { |
|
||||||
api.CountBroadcastChat() |
|
||||||
session.Broadcast(chat) |
|
||||||
} |
|
||||||
} else { |
|
||||||
if msg.Status != nil { |
|
||||||
if msg.Status.ContactRequest != nil { |
|
||||||
if !api.Config.WithModule("contacts") { |
|
||||||
return |
|
||||||
} |
|
||||||
if err := api.contactrequestHandler(session, to, msg.Status.ContactRequest); err != nil { |
|
||||||
log.Println("Ignoring invalid contact request.", err) |
|
||||||
return |
|
||||||
} |
|
||||||
msg.Status.ContactRequest.Userid = session.Userid() |
|
||||||
} |
|
||||||
} else { |
|
||||||
api.CountUnicastChat() |
|
||||||
} |
|
||||||
|
|
||||||
session.Unicast(to, chat) |
|
||||||
if msg.Mid != "" { |
|
||||||
// Send out delivery confirmation status chat message.
|
|
||||||
session.Unicast(session.Id, &DataChat{To: to, Type: "Chat", Chat: &DataChatMessage{Mid: msg.Mid, Status: &DataChatStatus{State: "sent"}}}) |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
func (api *channellingAPI) HandleConference(session *Session, conference *DataConference) { |
|
||||||
// Check conference maximum size.
|
|
||||||
if len(conference.Conference) > maxConferenceSize { |
|
||||||
log.Println("Refusing to create conference above limit.", len(conference.Conference)) |
|
||||||
return |
|
||||||
} |
|
||||||
|
|
||||||
// Send conference update to anyone.
|
|
||||||
for _, id := range conference.Conference { |
|
||||||
if id != session.Id { |
|
||||||
session.Unicast(id, conference) |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
func (api *channellingAPI) HandleSessions(session *Session, sessions *DataSessionsRequest) (*DataSessions, error) { |
|
||||||
switch sessions.Type { |
|
||||||
case "contact": |
|
||||||
if !api.Config.WithModule("contacts") { |
|
||||||
return nil, NewDataError("contacts_not_enabled", "incoming contacts session request with contacts disabled") |
|
||||||
} |
|
||||||
userID, err := api.getContactID(session, sessions.Token) |
|
||||||
if err != nil { |
|
||||||
return nil, err |
|
||||||
} |
|
||||||
return &DataSessions{ |
|
||||||
Type: "Sessions", |
|
||||||
Users: api.GetUserSessions(session, userID), |
|
||||||
Sessions: sessions, |
|
||||||
}, nil |
|
||||||
case "session": |
|
||||||
id, err := session.attestation.Decode(sessions.Token) |
|
||||||
if err != nil { |
|
||||||
return nil, NewDataError("bad_attestation", err.Error()) |
|
||||||
} |
|
||||||
session, ok := api.GetSession(id) |
|
||||||
if !ok { |
|
||||||
return nil, NewDataError("no_such_session", "cannot retrieve session") |
|
||||||
} |
|
||||||
return &DataSessions{ |
|
||||||
Type: "Sessions", |
|
||||||
Users: []*DataSession{session.Data()}, |
|
||||||
Sessions: sessions, |
|
||||||
}, nil |
|
||||||
default: |
|
||||||
return nil, NewDataError("bad_request", "unknown sessions request type") |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
func (api *channellingAPI) HandleRoom(session *Session, room *DataRoom) (*DataRoom, error) { |
|
||||||
room, err := api.UpdateRoom(session, room) |
|
||||||
if err == nil { |
|
||||||
session.Broadcast(room) |
|
||||||
} |
|
||||||
return room, err |
|
||||||
} |
|
@ -0,0 +1,56 @@ |
|||||||
|
/* |
||||||
|
* Spreed WebRTC. |
||||||
|
* Copyright (C) 2013-2015 struktur AG |
||||||
|
* |
||||||
|
* This file is part of Spreed WebRTC. |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"net/http" |
||||||
|
"strconv" |
||||||
|
"time" |
||||||
|
|
||||||
|
"github.com/strukturag/spreed-webrtc/go/channelling" |
||||||
|
|
||||||
|
"github.com/gorilla/mux" |
||||||
|
) |
||||||
|
|
||||||
|
func makeImageHandler(buddyImages channelling.ImageCache, expires time.Duration) http.HandlerFunc { |
||||||
|
return func(w http.ResponseWriter, r *http.Request) { |
||||||
|
vars := mux.Vars(r) |
||||||
|
image := buddyImages.Get(vars["imageid"]) |
||||||
|
if image == nil { |
||||||
|
http.Error(w, "Unknown image", http.StatusNotFound) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
w.Header().Set("Content-Type", image.MimeType()) |
||||||
|
w.Header().Set("ETag", image.LastChangeID()) |
||||||
|
age := time.Now().Sub(image.LastChange()) |
||||||
|
if age >= time.Second { |
||||||
|
w.Header().Set("Age", strconv.Itoa(int(age.Seconds()))) |
||||||
|
} |
||||||
|
if expires >= time.Second { |
||||||
|
w.Header().Set("Expires", time.Now().Add(expires).Format(time.RFC1123)) |
||||||
|
w.Header().Set("Cache-Control", "public, no-transform, max-age="+strconv.Itoa(int(expires.Seconds()))) |
||||||
|
} |
||||||
|
|
||||||
|
http.ServeContent(w, r, "", image.LastChange(), image.Reader()) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,30 @@ |
|||||||
|
/* |
||||||
|
* Spreed WebRTC. |
||||||
|
* Copyright (C) 2013-2015 struktur AG |
||||||
|
* |
||||||
|
* This file is part of Spreed WebRTC. |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"net/http" |
||||||
|
) |
||||||
|
|
||||||
|
func mainHandler(w http.ResponseWriter, r *http.Request) { |
||||||
|
handleRoomView("", w, r) |
||||||
|
} |
@ -0,0 +1,91 @@ |
|||||||
|
/* |
||||||
|
* Spreed WebRTC. |
||||||
|
* Copyright (C) 2013-2015 struktur AG |
||||||
|
* |
||||||
|
* This file is part of Spreed WebRTC. |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"net/http" |
||||||
|
|
||||||
|
"github.com/strukturag/spreed-webrtc/go/channelling" |
||||||
|
|
||||||
|
"github.com/gorilla/mux" |
||||||
|
) |
||||||
|
|
||||||
|
func roomHandler(w http.ResponseWriter, r *http.Request) { |
||||||
|
vars := mux.Vars(r) |
||||||
|
|
||||||
|
handleRoomView(vars["room"], w, r) |
||||||
|
} |
||||||
|
|
||||||
|
func handleRoomView(room string, w http.ResponseWriter, r *http.Request) { |
||||||
|
var err error |
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "text/html; charset=UTF-8") |
||||||
|
w.Header().Set("Expires", "-1") |
||||||
|
w.Header().Set("Cache-Control", "private, max-age=0") |
||||||
|
|
||||||
|
csp := false |
||||||
|
|
||||||
|
if config.ContentSecurityPolicy != "" { |
||||||
|
w.Header().Set("Content-Security-Policy", config.ContentSecurityPolicy) |
||||||
|
csp = true |
||||||
|
} |
||||||
|
if config.ContentSecurityPolicyReportOnly != "" { |
||||||
|
w.Header().Set("Content-Security-Policy-Report-Only", config.ContentSecurityPolicyReportOnly) |
||||||
|
csp = true |
||||||
|
} |
||||||
|
|
||||||
|
scheme := "http" |
||||||
|
|
||||||
|
// Detect if the request was made with SSL.
|
||||||
|
ssl := r.TLS != nil |
||||||
|
proto, ok := r.Header["X-Forwarded-Proto"] |
||||||
|
if ok { |
||||||
|
ssl = proto[0] == "https" |
||||||
|
scheme = "https" |
||||||
|
} |
||||||
|
|
||||||
|
// Get languages from request.
|
||||||
|
langs := getRequestLanguages(r, []string{}) |
||||||
|
if len(langs) == 0 { |
||||||
|
langs = append(langs, "en") |
||||||
|
} |
||||||
|
|
||||||
|
// Prepare context to deliver to HTML..
|
||||||
|
context := &channelling.Context{Cfg: config, App: "main", Host: r.Host, Scheme: scheme, Ssl: ssl, Csp: csp, Languages: langs, Room: room} |
||||||
|
|
||||||
|
// Get URL parameters.
|
||||||
|
r.ParseForm() |
||||||
|
|
||||||
|
// Check if incoming request is a crawler which supports AJAX crawling.
|
||||||
|
// See https://developers.google.com/webmasters/ajax-crawling/docs/getting-started for details.
|
||||||
|
if _, ok := r.Form["_escaped_fragment_"]; ok { |
||||||
|
// Render crawlerPage template..
|
||||||
|
err = templates.ExecuteTemplate(w, "crawlerPage", &context) |
||||||
|
} else { |
||||||
|
// Render mainPage template.
|
||||||
|
err = templates.ExecuteTemplate(w, "mainPage", &context) |
||||||
|
} |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,79 @@ |
|||||||
|
/* |
||||||
|
* Spreed WebRTC. |
||||||
|
* Copyright (C) 2013-2015 struktur AG |
||||||
|
* |
||||||
|
* This file is part of Spreed WebRTC. |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"fmt" |
||||||
|
"net/http" |
||||||
|
"net/url" |
||||||
|
|
||||||
|
"github.com/strukturag/spreed-webrtc/go/channelling" |
||||||
|
|
||||||
|
"github.com/gorilla/mux" |
||||||
|
) |
||||||
|
|
||||||
|
func sandboxHandler(w http.ResponseWriter, r *http.Request) { |
||||||
|
vars := mux.Vars(r) |
||||||
|
// NOTE(longsleep): origin_scheme is window.location.protocol (eg. https:, http:).
|
||||||
|
originURL, err := url.Parse(fmt.Sprintf("%s//%s", vars["origin_scheme"], vars["origin_host"])) |
||||||
|
if err != nil || originURL.Scheme == "" || originURL.Host == "" { |
||||||
|
http.Error(w, "Invalid origin path", http.StatusBadRequest) |
||||||
|
return |
||||||
|
} |
||||||
|
origin := fmt.Sprintf("%s://%s", originURL.Scheme, originURL.Host) |
||||||
|
|
||||||
|
handleSandboxView(vars["sandbox"], origin, w, r) |
||||||
|
} |
||||||
|
|
||||||
|
func handleSandboxView(sandbox string, origin string, w http.ResponseWriter, r *http.Request) { |
||||||
|
w.Header().Set("Content-Type", "text/html; charset=UTF-8") |
||||||
|
w.Header().Set("Expires", "-1") |
||||||
|
w.Header().Set("Cache-Control", "private, max-age=0") |
||||||
|
|
||||||
|
sandboxTemplateName := fmt.Sprintf("%s_sandbox.html", sandbox) |
||||||
|
|
||||||
|
// Prepare context to deliver to HTML..
|
||||||
|
if t := templates.Lookup(sandboxTemplateName); t != nil { |
||||||
|
|
||||||
|
// CSP support for sandboxes.
|
||||||
|
var csp string |
||||||
|
switch sandbox { |
||||||
|
case "odfcanvas": |
||||||
|
csp = fmt.Sprintf("default-src 'none'; script-src %s; img-src data: blob:; style-src 'unsafe-inline'", origin) |
||||||
|
case "pdfcanvas": |
||||||
|
csp = fmt.Sprintf("default-src 'none'; script-src %s 'unsafe-eval'; img-src 'self' data: blob:; style-src 'unsafe-inline'", origin) |
||||||
|
default: |
||||||
|
csp = "default-src 'none'" |
||||||
|
} |
||||||
|
w.Header().Set("Content-Security-Policy", csp) |
||||||
|
|
||||||
|
// Prepare context to deliver to HTML..
|
||||||
|
context := &channelling.Context{Cfg: config, Origin: origin, Csp: true} |
||||||
|
err := t.Execute(w, &context) |
||||||
|
if err != nil { |
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError) |
||||||
|
} |
||||||
|
|
||||||
|
} else { |
||||||
|
http.Error(w, "404 Unknown Sandbox", http.StatusNotFound) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,59 @@ |
|||||||
|
/* |
||||||
|
* Spreed WebRTC. |
||||||
|
* Copyright (C) 2013-2015 struktur AG |
||||||
|
* |
||||||
|
* This file is part of Spreed WebRTC. |
||||||
|
* |
||||||
|
* This program is free software: you can redistribute it and/or modify |
||||||
|
* it under the terms of the GNU Affero General Public License as published by |
||||||
|
* the Free Software Foundation, either version 3 of the License, or |
||||||
|
* (at your option) any later version. |
||||||
|
* |
||||||
|
* This program is distributed in the hope that it will be useful, |
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||||
|
* GNU Affero General Public License for more details. |
||||||
|
* |
||||||
|
* You should have received a copy of the GNU Affero General Public License |
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"encoding/json" |
||||||
|
"net/http" |
||||||
|
"net/url" |
||||||
|
"strings" |
||||||
|
) |
||||||
|
|
||||||
|
func wellKnownHandler(w http.ResponseWriter, r *http.Request) { |
||||||
|
// Detect if the request was made with SSL.
|
||||||
|
ssl := r.TLS != nil |
||||||
|
scheme := "http" |
||||||
|
proto, ok := r.Header["X-Forwarded-Proto"] |
||||||
|
if ok { |
||||||
|
ssl = proto[0] == "https" |
||||||
|
} |
||||||
|
if ssl { |
||||||
|
scheme = "https" |
||||||
|
} |
||||||
|
|
||||||
|
// Construct our URL.
|
||||||
|
url := url.URL{ |
||||||
|
Scheme: scheme, |
||||||
|
Host: r.Host, |
||||||
|
Path: strings.TrimSuffix(config.B, "/"), |
||||||
|
} |
||||||
|
doc := &map[string]string{ |
||||||
|
"spreed-webrtc_endpoint": url.String(), |
||||||
|
} |
||||||
|
data, err := json.MarshalIndent(doc, "", " ") |
||||||
|
if err != nil { |
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError) |
||||||
|
} |
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json") |
||||||
|
w.Write(data) |
||||||
|
} |
@ -0,0 +1,17 @@ |
|||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"net/http" |
||||||
|
|
||||||
|
"github.com/strukturag/goacceptlanguageparser" |
||||||
|
) |
||||||
|
|
||||||
|
// Helper to retrieve languages from request.
|
||||||
|
func getRequestLanguages(r *http.Request, supportedLanguages []string) []string { |
||||||
|
acceptLanguageHeader, ok := r.Header["Accept-Language"] |
||||||
|
var langs []string |
||||||
|
if ok { |
||||||
|
langs = goacceptlanguageparser.ParseAcceptLanguage(acceptLanguageHeader[0], supportedLanguages) |
||||||
|
} |
||||||
|
return langs |
||||||
|
} |
Loading…
Reference in new issue