Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
.idea
.DS_Store
laplace
config.json
42 changes: 33 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ There are already possible solutions to share your computer screen, e.g. TeamVie
But most of them require installations of software or plugins.
What Laplace provides is a simple solution to this problem.
For users wanting to share their screen, all they need to do is to open a website page with their browsers, clicking some buttons, then share some session ID with their peers.
No installation or registration required.

#### Solving the latency problem

Expand All @@ -46,15 +45,37 @@ The server is only needed for serving frontends and for WebRTC signaling.

## Installation

Build from source

### Installation required to share keyboard and mouse
To do this we ensure that the client either has has a IPV6
address or a public IPV4 address.
We use the use the popular open repository known as [Barrier KVM](https://github.com/debauchee/barrier).

#### What is Barrier kvm?

Barrier is software that mimics the functionality of a KVM switch, which historically would allow you to use a single keyboard and mouse to control multiple computers by physically turning a dial on the box to switch the machine you're controlling at any given moment. Barrier does this in software, allowing you to tell it which machine to control by moving your mouse to the edge of the screen, or by using a keypress to switch focus to a different system.

#### Barrier KVM build status and links to install
|Platform |Build Status|
| --:|:-- |
|Linux |[![Build Status](https://dev.azure.com/debauchee/Barrier/_apis/build/status/debauchee.barrier?branchName=master&jobName=Linux%20Build)](https://dev.azure.com/debauchee/Barrier/_build/latest?definitionId=1&branchName=master)|
|Mac |[![Build Status](https://dev.azure.com/debauchee/Barrier/_apis/build/status/debauchee.barrier?branchName=master&jobName=Mac%20Build)](https://dev.azure.com/debauchee/Barrier/_build/latest?definitionId=1&branchName=master)|
|Windows Debug |[![Build Status](https://dev.azure.com/debauchee/Barrier/_apis/build/status/debauchee.barrier?branchName=master&jobName=Windows%20Build&configuration=Windows%20Build%20Debug)](https://dev.azure.com/debauchee/Barrier/_build/latest?definitionId=1&branchName=master)|
|Windows Release|[![Build Status](https://dev.azure.com/debauchee/Barrier/_apis/build/status/debauchee.barrier?branchName=master&jobName=Windows%20Build&configuration=Windows%20Build%20Release%20with%20Release%20Installer)](https://dev.azure.com/debauchee/Barrier/_build/latest?definitionId=1&branchName=master)|
|Snap |[![Snap Status](https://build.snapcraft.io/badge/debauchee/barrier.svg)](https://build.snapcraft.io/user/debauchee/barrier)|


### Build from source

```bash
$ git clone https://github.com/adamyordan/laplace.git
$ cd laplace && go build -o laplace main.go
$ export LAPLACE = $PATH
$ ./laplace --help
$ ./laplace -setconfig
```

OR, pull the pre-built docker image
### OR, pull the pre-built docker image (Barrier KVM not supported yet)

```bash
$ docker pull adamyordan/laplace
Expand All @@ -70,20 +91,23 @@ Note that you sometimes need to run HTTPs in order for browser to connect to web
```bash
$ ./laplace --help
-addr string
Listen address (default "0.0.0.0:443")
Listen address (default "0.0.0.0:443")
-certFile string
TLS cert file (default "files/server.crt")
TLS cert file (default "files/server.crt")
-keyFile string
TLS key file (default "files/server.key")
TLS key file (default "files/server.key")
-setconfig
Generates a config file
-tls
Use TLS (default true)
Use TLS
```

By default, you can run the executable without any argument to listen to TLS port 443.
A self-signed certificate files are provided to ease up development.
A self-signed certificate files are provided to ease up development. If you want to run
with barrier KVM. Run as non-root.

```bash
$ ./laplace
$ ./laplace -tls
2020/03/25 01:01:10 Listening on TLS: 0.0.0.0:443
```

Expand Down
115 changes: 115 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package config

import (
"github.com/spf13/viper"
"os"
"os/user"
)

var (
defaultPath string
defaults = map[string]interface{}{
"SystemUsername": "",
"BarrierHostName": "",
}
configName = "config"
configType = "json"
configFile = "config.json"
configPaths []string
)

type Config struct {
SystemUsername string
BarrierHostName string
}

// Exists reports whether the named file or directory exists.
func fileExists(name string) bool {
if _, err := os.Stat(name); err != nil {
if os.IsNotExist(err) {
return false
}
}
return true
}

// SetDefaults This function to be called only during a
// make install
func SetDefaults() error {
//Getting Current Directory from environment variable
curDir := os.Getenv("LAPLACE")

//Setting current directory to default path
defaultPath = curDir + "/"

// Get system username
user ,err := user.Current()
if err != nil {
return err
}

// Get Hostname
name, err := os.Hostname()
if err != nil {
return err
}

//Setting default paths for the config file
defaults["SystemUsername"] = user.Username
defaults["BarrierHostName"] = name

//Paths to search for config file
configPaths = append(configPaths, defaultPath)

if fileExists(defaultPath + "config.json") {
err = os.Remove(defaultPath + "config.json")
if err != nil {
return err
}
}

//Calling configuration file
_, err = ConfigInit()
if err != nil {
return err
}
return nil
}

func ConfigInit()(*Config,error) {

curDir := os.Getenv("LAPLACE")
//Setting current directory to default path
defaultPath = curDir + "/"
//Paths to search for config file
configPaths = append(configPaths, defaultPath)

//Add all possible configurations paths
for _,v := range configPaths {
viper.AddConfigPath(v)
}

//Read config file
if err := viper.ReadInConfig(); err != nil {
// If the error thrown is config file not found
//Sets default configuration to viper
for k,v := range defaults {
viper.SetDefault(k,v)
}
viper.SetConfigName(configName)
viper.SetConfigFile(configFile)
viper.SetConfigType(configType)

if err = viper.WriteConfig(); err != nil {
return nil,err
}
}

// Adds configuration to the struct
var config Config
if err := viper.Unmarshal(&config); err != nil {
return nil,err
}

return &config,nil
}
20 changes: 20 additions & 0 deletions config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

package config

import (
"testing"
)

func TestConfigInit(t *testing.T) {
_,err := ConfigInit()
if err != nil {
t.Error(err)
}
}

func TestSetDefaults(t *testing.T) {
err := SetDefaults()
if err != nil {
t.Error(err)
}
}
89 changes: 89 additions & 0 deletions core/barrier-kvm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Package core
// We will implement the popular open source project barrier kvm
// To ensure we can connect clients keyboard and mouse to the server
// while ScreenShare is taking place
package core

import (
"laplace/config"
"os/exec"
)

// Barrier It's preferred that the IP address used is a IPV6 address
type Barrier struct {
NodeName string
IPAddress string
Mode string
Process *exec.Cmd
}

// CreateBarrierSession Command to run "barrier.barrierc --debug INFO -f 192.168.0.175"
func (b *Barrier)CreateBarrierSession() error {
//Checks if barrier client exists

if err := DetectBarrier(); err != nil {
return err
}

//Get username from config file
configResp, err := config.ConfigInit()
if err != nil {
return err
}

cmd := exec.Command("sudo","-u",configResp.SystemUsername,"barrier.barrierc","-f","--debug", "DEBUG" ,"--log", "/tmp/barrier.log",b.IPAddress)

// USE THE FOLLOWING TO DEBUG
//cmdReader, err := cmd.StdoutPipe()
//if err != nil {
// fmt.Fprintln(os.Stderr, "Error creating StdoutPipe for Cmd", err)
// return
//}
//
//// the following is used to print output of the command
//// as it makes progress...
//scanner := bufio.NewScanner(cmdReader)
//go func() {
// for scanner.Scan() {
// fmt.Printf("%s\n", scanner.Text())
// //
// // TODO:
// // send output to server
// }
//}()
//
//if err := cmd.Start(); err != nil {
// return err
//}

if err := cmd.Start(); err != nil {
return err
}

println(cmd.Path)


// Saves the state of the command in the struct
b.Process = cmd
return nil
}

// DeleteBarrierSession Deletes barrier client session running
func (b *Barrier)DeleteBarrierSession() error {
// Halts the process
cmd := exec.Command("pkill" ,"barrierc")
if err := cmd.Run(); err != nil {
return err
}

return nil
}

// DetectBarrier This function ensures that the server has barrier client installed
func DetectBarrier() error {
_, err := exec.LookPath("barrier.barrierc")
if err != nil {
return err
}
return nil
}
31 changes: 31 additions & 0 deletions core/barrier-kvm_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package core

import (
"testing"
"time"
)

// To run this test ensure you have barrier
// installed
func TestDetectBarrier(t *testing.T) {
err := DetectBarrier()
if err != nil {
t.Error()
}
}

func TestBarrier_CreateBarrierSession_DeleteBarrierSession(t *testing.T) {
var testIP Barrier
// Change this with the test machine controlling the
// keyboard and mouse
testIP.IPAddress = "192.168.0.175"
if err := testIP.CreateBarrierSession(); err != nil {
t.Error()
}
// Create delay
time.Sleep(5 * time.Second)

if err := testIP.DeleteBarrierSession(); err != nil {
t.Error()
}
}
3 changes: 2 additions & 1 deletion core/room.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ type Room struct {
ID string
Sessions map[string]*StreamSession
CallerConn *websocket.Conn
BarrierSession *Barrier
}

type StreamSession struct {
Expand Down Expand Up @@ -50,7 +51,7 @@ func RemoveRoom(id string) {
}

func (room *Room) GetSession(id string) *StreamSession {
return room.Sessions[id]
return room.Sessions[id]
}

func (room *Room) NewSession(calleeConn *websocket.Conn) *StreamSession {
Expand Down
Loading