64 changed files with 1568 additions and 936 deletions
@ -1,12 +0,0 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -1,4 +1,4 @@
|
||||
package main |
||||
package channelling |
||||
|
||||
import ( |
||||
"errors" |
@ -0,0 +1,60 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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