Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
332a6ce
implement datahandling triggers through rabbitmq only
julie-is-late Feb 12, 2017
6dcae46
change worker prefetch count to be configurable
julie-is-late Feb 15, 2017
3a9ce65
fix issues where we weren't ack'ing in certain cases where we failed …
julie-is-late Feb 16, 2017
53b73cb
raise default worker multiplier, restart workers on failure
julie-is-late Feb 16, 2017
a1b279d
add debug statement to closure send
julie-is-late Feb 16, 2017
3d0f52a
remove hostname from websocket rabbit queue name
julie-is-late Feb 16, 2017
e3605ad
switch websockets to keep host specific origins across servers
julie-is-late Feb 17, 2017
3e7efdb
implement loading cert keys for signing locally so tokens can be veri…
julie-is-late Feb 21, 2017
6d11111
fix amateur hour level copy by reference mistake
julie-is-late Feb 22, 2017
5d8a673
reset max runners
julie-is-late Feb 22, 2017
b2d721c
cleanup error messages so i can debug
julie-is-late Feb 22, 2017
06cf674
add wiggle room to token validation check
julie-is-late Feb 22, 2017
d59d287
made acking error fatal
julie-is-late Mar 15, 2017
f7d0539
cleanup of errors
julie-is-late Mar 16, 2017
15585a3
Added myers diff algorithm
ObsessiveOrange Feb 6, 2017
be302ba
Added patch consolidation
ObsessiveOrange Feb 10, 2017
1e1844d
Corrected a few bugs in consolidation, added a large test case
ObsessiveOrange Feb 10, 2017
6a9b84f
Added another long-file test
ObsessiveOrange Feb 10, 2017
e264227
Updated consolidation to use cases, deleted myersdiff files
ObsessiveOrange Feb 12, 2017
9a7a221
Added EOF, reverted some unintended refactors
ObsessiveOrange Feb 12, 2017
5452b02
Cleanup of code
ObsessiveOrange Mar 15, 2017
8049b66
Added comments to match up with OT Effects table
ObsessiveOrange Mar 16, 2017
2bff7e0
Updated OT algorithm
ObsessiveOrange Mar 23, 2017
7a67e0a
Corrected bug in OT case 3d
ObsessiveOrange Mar 24, 2017
636b97d
Allow diffs to be empty
ObsessiveOrange Mar 24, 2017
4114f0f
Fixed another bug in OT case 3d
ObsessiveOrange Mar 25, 2017
e76b740
Ported new transform function, changed API for file change to only ta…
ObsessiveOrange Mar 26, 2017
e76e0ea
updated patching no-op length generation
ObsessiveOrange Mar 27, 2017
bca5ac7
Added handling of no-action patches
ObsessiveOrange Mar 27, 2017
a746bb6
git push -fPrevent logging of user/passwords
ObsessiveOrange Mar 27, 2017
7be0f21
Changed debug request message to be a string
ObsessiveOrange Mar 27, 2017
9aaf95b
Updated consolehook to print debug message
ObsessiveOrange Mar 27, 2017
242e0da
Set file logging to JSON, console logging to textformatter
ObsessiveOrange Mar 27, 2017
b52fb0d
Prevent users from changing their own permissions
ObsessiveOrange Mar 28, 2017
71ff21d
Changed to use go autocert
ObsessiveOrange Mar 30, 2017
a6b1712
Added capnet service permissions
ObsessiveOrange Mar 31, 2017
e44aee7
Add todo
ObsessiveOrange Apr 1, 2017
4a012dc
Updated with pprof
ObsessiveOrange Apr 3, 2017
2099016
Patch consolidation + OT rebuild
ObsessiveOrange Apr 3, 2017
d1a7cc6
implement datahandling triggers through rabbitmq only
julie-is-late Feb 12, 2017
34d8a06
change worker prefetch count to be configurable
julie-is-late Feb 15, 2017
f9a0522
fix issues where we weren't ack'ing in certain cases where we failed …
julie-is-late Feb 16, 2017
edabaec
raise default worker multiplier, restart workers on failure
julie-is-late Feb 16, 2017
4291168
add debug statement to closure send
julie-is-late Feb 16, 2017
08d9881
remove hostname from websocket rabbit queue name
julie-is-late Feb 16, 2017
d9cb94c
switch websockets to keep host specific origins across servers
julie-is-late Feb 17, 2017
f7bbceb
implement loading cert keys for signing locally so tokens can be veri…
julie-is-late Feb 21, 2017
5f9aef0
fix amateur hour level copy by reference mistake
julie-is-late Feb 22, 2017
39db666
reset max runners
julie-is-late Feb 22, 2017
ad755c8
cleanup error messages so i can debug
julie-is-late Feb 22, 2017
0247644
add wiggle room to token validation check
julie-is-late Feb 22, 2017
69c6906
made acking error fatal
julie-is-late Mar 15, 2017
998065d
cleanup of errors
julie-is-late Mar 16, 2017
695c24f
Merged changes from test
ObsessiveOrange Apr 3, 2017
df2295a
add fixme
julie-is-late Nov 4, 2017
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,4 @@ data
*.swp
/.vscode/
/bin/
*.bkpignore
4 changes: 3 additions & 1 deletion config/defaults/server.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@
"Port": 8000,
"ProjectPath" : "./data/ProjectFiles/",
"LogLevel": "Warn",
"TokenValidity": "1h"
"TokenValidity": "1h",
"RSAPrivateKeyLocation": "",
"RSAPrivateKeyPassword": ""
}
64 changes: 64 additions & 0 deletions modules/config/authconfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package config

import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"io/ioutil"

"github.com/CodeCollaborate/Server/utils"
)

func rsaConfigSetup(rsaPrivateKeyLocation, rsaPrivateKeyPassword string) (*rsa.PrivateKey, error) {
if rsaPrivateKeyLocation == "" {
utils.LogWarn("No RSA Key given, generating temp one", nil)
return GenRSA(4096)
}

priv, err := ioutil.ReadFile(rsaPrivateKeyLocation)
if err != nil {
utils.LogWarn("No RSA private key found, generating temp one", nil)
return GenRSA(4096)
}

privPem, _ := pem.Decode(priv)
var pemBytes []byte

if privPem.Type != "RSA PRIVATE KEY" {
utils.LogWarn("RSA private key is of the wrong type", utils.LogFields{
"Pem Type": privPem.Type,
})
}

if rsaPrivateKeyPassword != "" {
pemBytes, err = x509.DecryptPEMBlock(privPem, []byte(rsaPrivateKeyPassword))
} else {
pemBytes = privPem.Bytes
}

var parsedKey interface{}
if parsedKey, err = x509.ParsePKCS1PrivateKey(pemBytes); err != nil {
if parsedKey, err = x509.ParsePKCS8PrivateKey(pemBytes); err != nil { // note this returns type `interface{}`
utils.LogError("Unable to parse RSA private key, generating a temp one", err, utils.LogFields{})
return GenRSA(4096)
}
}

var privateKey *rsa.PrivateKey
var ok bool
if privateKey, ok = parsedKey.(*rsa.PrivateKey); !ok {
utils.LogError("Unable to parse RSA key, generating a temp one", err, utils.LogFields{})
return GenRSA(4096)
}

utils.LogInfo("Loaded RSA key from file", utils.LogFields{})
return privateKey, nil
}

// GenRSA returns a new RSA key of bits length
func GenRSA(bits int) (*rsa.PrivateKey, error) {
key, err := rsa.GenerateKey(rand.Reader, bits)
utils.LogFatal("Failed to generate signing key", err, nil)
return key, err
}
18 changes: 18 additions & 0 deletions modules/config/authconfig_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package config

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestAuthConfigSetup(t *testing.T) {
SetConfigDir("../../config")
err := LoadConfig()
assert.NoError(t, err, "error initializing config needed for password")

key, err := rsaConfigSetup("../../config/id_rsa", config.ServerConfig.RSAPrivateKeyPassword)
assert.Nil(t, err, "error loading rsa key")
assert.NotNil(t, key, "key was nil")
assert.NoError(t, key.Validate(), "key could not be validated")
}
12 changes: 9 additions & 3 deletions modules/config/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import (
"path/filepath"
"time"

"github.com/CodeCollaborate/Server/utils"
log "github.com/Sirupsen/logrus"
"github.com/kr/pretty"

"github.com/CodeCollaborate/Server/utils"
)

/**
Expand All @@ -35,7 +35,8 @@ func LoadConfig() error {

if err == nil {
utils.LogInfo("Loaded Configuration", utils.LogFields{
"ServerConfig": pretty.Sprint(config.ServerConfig),
//"ServerConfig": pretty.Sprint(config.ServerConfig),
// TODO: remove secret fields from config and then print again
})
setLogLevel()
}
Expand Down Expand Up @@ -69,6 +70,10 @@ func setLogLevel() {
}
}

func init() {
log.SetFormatter(&log.TextFormatter{DisableColors: true})
}

// EnableLoggingToFile redirects logger output to a logfile in the config's LogDir.
// A new logfile will be created each time this method is called.
func EnableLoggingToFile(logDir string) {
Expand All @@ -77,6 +82,7 @@ func EnableLoggingToFile(logDir string) {
logFile := filepath.Join(logDir, fmt.Sprintf("%d.%02d.%02d.%02d.%02d.log", time.Now().Year(), time.Now().Month(), time.Now().Day(), time.Now().Hour(), time.Now().Minute()))

log.Infof("Logging to %s", logFile)
log.SetFormatter(&log.JSONFormatter{})
f, err := os.OpenFile(logFile, os.O_WRONLY|os.O_CREATE, 0755)
if err != nil {
log.Error("Failed to setup logging to file")
Expand Down
19 changes: 13 additions & 6 deletions modules/config/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import (
"io/ioutil"
"os"
"path/filepath"
"reflect"
"testing"

"github.com/stretchr/testify/assert"
)

func TestGetConfig(t *testing.T) {
tmpDir := createTmpDir(t, ".", "test-config-files")
defer os.RemoveAll(tmpDir)

// ensure configDir is set to the default. other tests could have run before and set it elsewhere
SetConfigDir("./config")
err := LoadConfig()
if err == nil {
t.Fatal("Config dir not set yet; ./config does not exist. Should have failed.")
Expand Down Expand Up @@ -42,10 +45,16 @@ func TestGetConfig(t *testing.T) {
t.Fatal(err)
}

assert.Nil(t, data.ServerConfig.rsaKey, "Ensure rsaKey lazily loaded")
privateKey := data.ServerConfig.RSAKey()
assert.NotNil(t, data.ServerConfig.rsaKey, "Ensure rsaKey lazily loaded")
assert.ObjectsAreEqual(privateKey, data.ServerConfig.rsaKey)

expected := &Config{
ServerConfig: ServerCfg{
Name: "CodeCollaborate",
Port: 80,
Name: "CodeCollaborate",
Port: 80,
rsaKey: privateKey, // cheating
},
ConnectionConfig: ConnCfgMap{
"MySQL": ConnCfg{
Expand All @@ -63,7 +72,5 @@ func TestGetConfig(t *testing.T) {
},
}

if !reflect.DeepEqual(data, expected) {
t.Fatalf("Parsed data incorrect. Expected: \n%v\n Actual: \n%v\n", data, expected)
}
assert.ObjectsAreEqualValues(expected, data)
}
28 changes: 27 additions & 1 deletion modules/config/models.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package config

import "time"
import (
"crypto/rsa"
"time"

"github.com/CodeCollaborate/Server/utils"
)

/**
* Models for the configuration CodeCollaborate Server.
Expand All @@ -18,14 +23,21 @@ type Config struct {
// ServerCfg contains various config items that pertain to the server
type ServerCfg struct {
Name string
Host string
Port uint16
ProjectPath string
DisableAuth bool
UseTLS bool
LogLevel string
TokenValidity string
MinBufferLength int
MaxBufferLength int

// RSA key
RSAPrivateKeyLocation string
RSAPrivateKeyPassword string
rsaKey *rsa.PrivateKey

// Parsed validity
tokenValidityDuration time.Duration
}
Expand All @@ -41,6 +53,20 @@ func (cfg ServerCfg) TokenValidityDuration() (time.Duration, error) {
return cfg.tokenValidityDuration, err
}

// RSAKey returns the RSA key the server should use for signing tokens
func (cfg *ServerCfg) RSAKey() *rsa.PrivateKey {
if cfg.rsaKey != nil {
return cfg.rsaKey
}

var err error
cfg.rsaKey, err = rsaConfigSetup(config.ServerConfig.RSAPrivateKeyLocation, config.ServerConfig.RSAPrivateKeyPassword)
if err != nil {
utils.LogFatal("Unable to load/generate RSA key", err, utils.LogFields{})
}
return cfg.rsaKey
}

// ConnCfg represents the information required to make a connection
type ConnCfg struct {
Host string
Expand Down
32 changes: 26 additions & 6 deletions modules/datahandling/authentication.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package datahandling

import (
"crypto/rsa"
"errors"
"fmt"
"strings"
"time"

"github.com/CodeCollaborate/Server/modules/config"
"github.com/dgrijalva/jwt-go"

"github.com/CodeCollaborate/Server/modules/config"
"github.com/CodeCollaborate/Server/utils"
)

type tokenPayload struct {
Expand All @@ -16,6 +19,22 @@ type tokenPayload struct {
Validity int64
}

var rsaKey *rsa.PrivateKey

func getRsaKey() *rsa.PrivateKey {
if rsaKey != nil {
return rsaKey
}

cfg := config.GetConfig()
if cfg == nil {
utils.LogFatal("Failed to load RSA key from config", errors.New("config not initialized"), utils.LogFields{})
}

rsaKey = cfg.ServerConfig.RSAKey()
return rsaKey
}

// Valid is the (unused) method to determine if the token is valid. however, since we need to have a reference
// to the abstract request, we cannot do validation here. Token validation has been shifted to the authenticate
// method. This is here for conformance to the token.Claims interface.
Expand All @@ -26,10 +45,10 @@ func (tokenPayload) Valid() error {
func authenticate(abs abstractRequest) error {
token, err := jwt.ParseWithClaims(abs.SenderToken, &tokenPayload{}, func(token *jwt.Token) (interface{}, error) {
// Don't forget to validate the alg is what you expect:
if _, ok := token.Method.(*jwt.SigningMethodECDSA); !ok {
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
return nil, fmt.Errorf("ParseWithClaims - Unexpected signing method: %v", token.Header["alg"])
}
return &privKey.PublicKey, nil
return &getRsaKey().PublicKey, nil
})
if err != nil {
return fmt.Errorf("authenticate - failed to parse token: %s", err)
Expand All @@ -40,7 +59,8 @@ func authenticate(abs abstractRequest) error {
if !strings.EqualFold(claims.Username, abs.SenderID) {
return errors.New("authenticate - senderID did not match token username")
}
if time.Unix(claims.CreationTime, 0).After(time.Now()) {
// check if token is valid yet, but now with some wiggle room
if time.Unix(claims.CreationTime, 0).Add(-1 * time.Minute).After(time.Now()) {
return errors.New("authenticate - token not valid yet")
}
if !time.Unix(claims.Validity, 0).After(time.Now()) {
Expand All @@ -58,11 +78,11 @@ func newAuthToken(username string) (string, error) {
return "", err
}

token := jwt.NewWithClaims(jwt.SigningMethodES256, tokenPayload{
token := jwt.NewWithClaims(jwt.SigningMethodRS512, tokenPayload{
Username: username,
CreationTime: time.Now().Unix(),
Validity: time.Now().Add(tokenValidityDuration).Unix(),
})

return token.SignedString(privKey)
return token.SignedString(getRsaKey())
}
Loading