Complete overhaul, remove all things related to modules

This commit is contained in:
ChronosX88 2021-03-30 22:40:02 +03:00
parent c0ed5c7acf
commit e6199a1a4f
Signed by: ChronosXYZ
GPG Key ID: 085A69A82C8C511A
32 changed files with 493 additions and 539 deletions

8
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/zirconium-go.iml" filepath="$PROJECT_DIR$/.idea/zirconium-go.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

8
.idea/watcherTasks.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectTasksOptions">
<enabled-global>
<option value="go fmt" />
</enabled-global>
</component>
</project>

9
.idea/zirconium-go.iml Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 ChronosX88
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,3 +1,11 @@
# Zirconium
**Zirconium** is a Cadmium protocol server experimental implementation
Zirconium is experimental serverside implementation of Cadmium protocol in Go.
## Contributing
Feel free to open PRs. If you found the bug, please let us know at our [bug tracker](https://github.com/cadmium-im/zirconium-go/issues).
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

View File

@ -5,34 +5,22 @@ import (
"flag"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
core "github.com/ChronosX88/zirconium/core"
"github.com/cadmium-im/zirconium-go/core"
"github.com/google/logger"
"github.com/gorilla/mux"
"github.com/gorilla/websocket"
"github.com/pelletier/go-toml"
)
var connectionHandler = core.NewConnectionHandler()
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
func main() {
var cfg core.ServerConfig
var cfg core.Config
var configPath string
var generateConfig bool
flag.StringVar(&configPath, "config", "", "Path to config")
flag.BoolVar(&generateConfig, "gen_config", false, "Generate the config")
flag.Parse()
if generateConfig == true {
sampleConfig := &core.ServerConfig{}
sampleConfig := &core.Config{}
val, err := toml.Marshal(sampleConfig)
if err != nil {
logger.Errorf("Failed to generate config: %s", err.Error())
@ -61,30 +49,14 @@ func main() {
os.Exit(1)
}
core.InitializeContext(cfg.ServerDomain, cfg.PluginsDirPath, cfg.EnabledPlugins)
router := mux.NewRouter()
router.HandleFunc("/", func(response http.ResponseWriter, request *http.Request) {
response.Write([]byte("Zirconium server is up and running!"))
}).Methods("GET")
router.HandleFunc("/ws", wsHandler)
ac := core.NewAppContext(&cfg)
logger.Info("Zirconium successfully started!")
logger.Fatal(http.ListenAndServe(":8844", router))
logger.Fatal(ac.Run())
}
func wsHandler(w http.ResponseWriter, r *http.Request) {
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Fatal(err)
}
connectionHandler.HandleNewConnection(ws)
}
func validateConfig(config *core.ServerConfig) error {
if config.ServerDomain == "" {
return errors.New("server domain isn't specified")
} else if config.PluginsDirPath == "" {
return errors.New("plugin directory path isn't specified")
func validateConfig(config *core.Config) error {
if config.ServerID == "" {
return errors.New("server id isn't specified")
}
return nil
}

77
core/app_context.go Normal file
View File

@ -0,0 +1,77 @@
package core
import (
"context"
"fmt"
"github.com/google/logger"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
)
type AppContext struct {
router *Router
authManager *AuthManager
connectionHandler *ConnectionHandler
websocketServer *WebsocketServer
cfg *Config
database *mongo.Database
userManager *UserManager
}
func NewAppContext(cfg *Config) *AppContext {
var err error
appContext := &AppContext{}
appContext.cfg = cfg
appContext.connectToDatabase()
router, err := NewRouter(appContext)
if err != nil {
logger.Fatalf("Unable to initialize router: %s", err.Error())
}
appContext.router = router
authManager, err := NewAuthManager()
if err != nil {
logger.Fatalf("Unable to initialize authentication manager: %s", err.Error())
}
appContext.authManager = authManager
um := NewUserManager(appContext.database)
appContext.userManager = um
connHandler := NewConnectionHandler(router)
appContext.connectionHandler = connHandler
wss := NewWebsocketServer(cfg, connHandler)
appContext.websocketServer = wss
return appContext
}
func (ac *AppContext) connectToDatabase() {
ctx := context.TODO()
dbUri := fmt.Sprintf("mongodb://%s:%s@%s:%d", ac.cfg.Mongo.User, ac.cfg.Mongo.Password, ac.cfg.Mongo.Host, ac.cfg.Mongo.Port)
opts := options.Client().ApplyURI(dbUri)
err := opts.Validate()
if err != nil {
logger.Fatalf("invalid database config: %s", err)
}
mongoClient, err := mongo.Connect(ctx, opts)
if err != nil {
logger.Fatalf("cannot connect to mongo database: %s", err)
}
err = mongoClient.Ping(ctx, readpref.Primary())
if err != nil {
logger.Fatalf("cannot connect to mongo database: %s", err)
}
db := mongoClient.Database(ac.cfg.Mongo.Database)
ac.database = db
}
func (ac *AppContext) Run() error {
// TODO
return nil
}

View File

@ -5,6 +5,8 @@ import (
"fmt"
"time"
"github.com/cadmium-im/zirconium-go/core/models"
"github.com/dgrijalva/jwt-go"
)
@ -18,8 +20,8 @@ type AuthManager struct {
}
type JWTCustomClaims struct {
EntityID string `json:"entityID"`
DeviceID string `json:"deviceID"`
EntityID []*models.EntityID `json:"entityID"`
DeviceID string `json:"deviceID"`
jwt.StandardClaims
}
@ -33,11 +35,12 @@ func NewAuthManager() (*AuthManager, error) {
return am, nil
}
func (am *AuthManager) CreateNewToken(entityID, deviceID string, tokenExpireTimeDuration time.Duration) (string, error) {
func (am *AuthManager) CreateNewToken(entityID *models.EntityID, deviceID string, tokenExpireTimeDuration time.Duration) (string, error) {
timeNow := time.Now()
expiringTime := timeNow.Add(tokenExpireTimeDuration)
claims := JWTCustomClaims{
entityID,
[]*models.EntityID{entityID},
deviceID,
jwt.StandardClaims{
ExpiresAt: time.Date(
@ -61,19 +64,23 @@ func (am *AuthManager) CreateNewToken(entityID, deviceID string, tokenExpireTime
return tokenString, nil
}
func (am *AuthManager) ValidateToken(tokenString string) (bool, string, string, error) {
func (am *AuthManager) ValidateToken(tokenString string) (*JWTCustomClaims, error) {
token, err := jwt.ParseWithClaims(tokenString, &JWTCustomClaims{}, func(token *jwt.Token) (interface{}, error) {
// Don't forget to validate the alg is what you expect:
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
// hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key")
return []byte(am.signingKey), nil
})
if claims, ok := token.Claims.(*JWTCustomClaims); ok && token.Valid {
return true, claims.EntityID, claims.DeviceID, nil
if err != nil {
return nil, err
}
return false, "", "", err
if claims, ok := token.Claims.(*JWTCustomClaims); ok && token.Valid {
return claims, nil
}
return nil, err
}

View File

@ -1,4 +0,0 @@
package core
// BuiltinPlugins is a list of builtin plugins
var BuiltinPlugins = map[string]Module{}

View File

@ -1,12 +1,18 @@
package core
type ServerConfig struct {
// A list of enabled plugins (or extensions) in server
EnabledPlugins []string `toml:"enabledPlugins" comment:"A list of enabled plugins (or extensions) in server"`
// Server domain name (e.g. example.com)
ServerDomain string `toml:"serverDomain" comment:"Server domain name (e.g. example.com)"`
// Path to directory with plugin executables
PluginsDirPath string `toml:"pluginsDirPath" comment:"Path to directory with plugin executables"`
type Config struct {
ServerDomains []string `comment:"Server domain names (e.g. example.com)"`
ServerID string
Websocket struct {
Host string
Port int
Endpoint string
}
Mongo struct {
Host string
Port int
User string
Password string
Database string
}
}

View File

@ -1,26 +1,28 @@
package core
import (
"github.com/ChronosX88/zirconium/core/models"
"github.com/cadmium-im/zirconium-go/core/models"
"github.com/google/logger"
"github.com/google/uuid"
"github.com/gorilla/websocket"
)
type ConnectionHandler struct {
connections map[string]*OriginC2S
router *Router
connections map[string]*Session
}
func NewConnectionHandler() *ConnectionHandler {
func NewConnectionHandler(r *Router) *ConnectionHandler {
return &ConnectionHandler{
connections: make(map[string]*OriginC2S),
router: r,
connections: make(map[string]*Session),
}
}
func (ch *ConnectionHandler) HandleNewConnection(wsocket *websocket.Conn) {
uuid, _ := uuid.NewRandom()
uuidStr := uuid.String()
o := &OriginC2S{
randomUUID, _ := uuid.NewRandom()
uuidStr := randomUUID.String()
o := &Session{
wsConn: wsocket,
connID: uuidStr,
}
@ -31,11 +33,11 @@ func (ch *ConnectionHandler) HandleNewConnection(wsocket *websocket.Conn) {
err := o.wsConn.ReadJSON(&msg)
if err != nil {
delete(ch.connections, o.connID)
o.wsConn.Close()
_ = o.wsConn.Close()
logger.Infof("Connection %s was closed. (Reason: %s)", o.connID, err.Error())
break
}
router.RouteMessage(o, msg)
ch.router.RouteMessage(o, msg)
}
}()
logger.Infof("Connection %s was created", o.connID)

View File

@ -1,41 +0,0 @@
package core
import (
"github.com/google/logger"
)
var (
moduleMgr ModuleAPI
router *Router
authManager *AuthManager
serverDomain string
pluginManager *PluginManager
)
func InitializeContext(sDomain string, pluginsDirPath string, enabledPlugins []string) {
var err error
moduleMgr, err = NewModuleManager()
if err != nil {
logger.Fatalf("Unable to initialize module manager: %s", err.Error())
}
router, err = NewRouter()
if err != nil {
logger.Fatalf("Unable to initialize router: %s", err.Error())
}
authManager, err = NewAuthManager()
if err != nil {
logger.Fatalf("Unable to initialize authentication manager: %s", err.Error())
}
serverDomain = sDomain
for _, v := range BuiltinPlugins {
go v.Initialize(ModuleAPI(moduleMgr)) // Initialize builtin plugins
}
pluginManager = NewPluginManager()
for _, v := range enabledPlugins {
pluginManager.StartPlugin(pluginsDirPath, v, moduleMgr.(*ModuleManager))
}
}

11
core/models/auth/auth.go Normal file
View File

@ -0,0 +1,11 @@
package auth
type AuthRequest struct {
Type string `json:"type"`
Fields map[string]interface{} `json:"fields"`
}
type AuthResponse struct {
Token string `json:"token"`
DeviceID string `json:"deviceID"`
}

View File

@ -5,13 +5,12 @@ type BaseMessage struct {
ID string `json:"id"`
MessageType string `json:"type"`
From string `json:"from"`
To string `json:"to"`
To []string `json:"to"`
Ok bool `json:"ok"`
AuthToken string `json:"authToken"`
Payload map[string]interface{} `json:"payload"`
}
func NewBaseMessage(id, messageType, from, to string, ok bool, payload map[string]interface{}) BaseMessage {
func NewBaseMessage(id, messageType, from string, to []string, ok bool, payload map[string]interface{}) BaseMessage {
return BaseMessage{
ID: id,
MessageType: messageType,

View File

@ -9,8 +9,8 @@ type EntityIDType string
const (
UsernameType EntityIDType = "@"
RoomAliasType EntityIDType = "#"
RoomIDType EntityIDType = "!"
ChatAliasType EntityIDType = "#"
ChatIDType EntityIDType = "!"
)
type EntityID struct {
@ -19,30 +19,52 @@ type EntityID struct {
ServerPart string
}
func NewEntityID(entityID string) *EntityID {
eID := &EntityID{}
switch EntityIDType(string(entityID[0])) {
func NewEntityIDFromString(entityID string) (*EntityID, error) {
eid := &EntityID{}
typ := string(entityID[0])
switch EntityIDType(typ) {
case UsernameType:
fallthrough
case ChatAliasType:
fallthrough
case ChatIDType:
{
eID.EntityIDType = UsernameType
}
case RoomAliasType:
{
eID.EntityIDType = RoomAliasType
}
case RoomIDType:
{
eID.EntityIDType = RoomIDType
eid.EntityIDType = EntityIDType(typ)
}
default:
return nil, fmt.Errorf("invalid entity id type: %s", typ)
}
localAndServerPart := strings.Split(entityID, "@")
if len(localAndServerPart) == 3 {
localAndServerPart = localAndServerPart[1:]
}
eID.LocalPart = localAndServerPart[0]
eID.ServerPart = localAndServerPart[1]
eid.LocalPart = localAndServerPart[0]
eid.ServerPart = localAndServerPart[1]
return eID
return eid, nil
}
func NewEntityID(typ, localPart, serverPart string) (*EntityID, error) {
eid := &EntityID{}
switch EntityIDType(typ) {
case UsernameType:
fallthrough
case ChatAliasType:
fallthrough
case ChatIDType:
{
eid.EntityIDType = EntityIDType(typ)
}
default:
return nil, fmt.Errorf("invalid entity id type: %s", typ)
}
eid.LocalPart = localPart
eid.ServerPart = serverPart
return eid, nil
}
func (eID *EntityID) String() string {

View File

@ -1,7 +1,7 @@
package models
type ProtocolError struct {
ErrCode string `json:"errCode"`
ErrText string `json:"errText"`
ErrPayload map[string]interface{} `json:"errPayload"`
ErrCode string `json:"code"`
ErrText string `json:"text"`
ErrPayload map[string]interface{} `json:"payload"`
}

View File

@ -1,17 +0,0 @@
package core
const (
ModuleInterfaceName = "Module"
)
type Module interface {
Initialize(moduleAPI ModuleAPI)
Name() string
Version() string
}
type ModuleRef struct {
F func() Module
}
type ModuleFunc func() Module

View File

@ -1,100 +0,0 @@
package core
import (
"reflect"
"sync"
"time"
"github.com/ChronosX88/zirconium/core/models"
)
type C2SMessageHandler struct {
HandlerFunc func(origin *OriginC2S, message models.BaseMessage)
AnonymousAllowed bool
}
type ModuleManager struct {
moduleMutex sync.Mutex
c2sMessageHandlers map[string][]*C2SMessageHandler
coreEventHandlers map[string][]func(sourceModuleName string, event map[string]interface{})
}
type ModuleAPI interface {
Hook(messageType string, anonymousAllowed bool, handlerFunc func(origin *OriginC2S, message models.BaseMessage))
HookInternalEvent(eventName string, handlerFunc func(sourceModuleName string, event map[string]interface{}))
Unhook(messageType string, handlerFunc func(origin *OriginC2S, message models.BaseMessage))
UnhookInternalEvent(eventName string, handlerFunc func(sourceModuleName string, event map[string]interface{}))
FireEvent(sourceModuleName string, eventName string, eventPayload map[string]interface{})
GenerateToken(entityID, deviceID string, tokenExpireTimeDuration time.Duration) (string, error)
GetServerDomain() string
}
func NewModuleManager() (ModuleAPI, error) {
var mm = &ModuleManager{
c2sMessageHandlers: make(map[string][]*C2SMessageHandler),
coreEventHandlers: make(map[string][]func(sourceModuleName string, event map[string]interface{})),
}
return mm, nil
}
func (mm *ModuleManager) Hook(messageType string, anonymousAllowed bool, handlerFunc func(origin *OriginC2S, message models.BaseMessage)) {
mm.moduleMutex.Lock()
mm.c2sMessageHandlers[messageType] = append(mm.c2sMessageHandlers[messageType], &C2SMessageHandler{
HandlerFunc: handlerFunc,
AnonymousAllowed: anonymousAllowed,
})
mm.moduleMutex.Unlock()
}
func (mm *ModuleManager) HookInternalEvent(eventName string, handlerFunc func(sourceModuleName string, event map[string]interface{})) {
mm.moduleMutex.Lock()
mm.coreEventHandlers[eventName] = append(mm.coreEventHandlers[eventName], handlerFunc)
mm.moduleMutex.Unlock()
}
func (mm *ModuleManager) Unhook(messageType string, handlerFunc func(origin *OriginC2S, message models.BaseMessage)) {
mm.moduleMutex.Lock()
defer mm.moduleMutex.Unlock()
var handlers = mm.c2sMessageHandlers[messageType]
if handlers != nil {
for i, v := range handlers {
if reflect.ValueOf(v.HandlerFunc).Pointer() == reflect.ValueOf(handlerFunc).Pointer() {
handlers[i] = handlers[len(handlers)-1]
handlers[len(handlers)-1] = nil
handlers = handlers[:len(handlers)-1]
mm.c2sMessageHandlers[messageType] = handlers
break
}
}
}
}
func (mm *ModuleManager) UnhookInternalEvent(eventName string, handlerFunc func(sourceModuleName string, event map[string]interface{})) {
mm.moduleMutex.Lock()
defer mm.moduleMutex.Unlock()
var handlers = mm.coreEventHandlers[eventName]
if handlers != nil {
for i, v := range handlers {
if reflect.ValueOf(v).Pointer() == reflect.ValueOf(handlerFunc).Pointer() {
handlers[i] = handlers[len(handlers)-1]
handlers[len(handlers)-1] = nil
handlers = handlers[:len(handlers)-1]
mm.coreEventHandlers[eventName] = handlers
break
}
}
}
}
func (mm *ModuleManager) FireEvent(sourceModuleName string, eventName string, eventPayload map[string]interface{}) {
router.RoutecoreEvent(sourceModuleName, eventName, eventPayload)
}
func (mm *ModuleManager) GenerateToken(entityID, deviceID string, tokenExpireTimeDuration time.Duration) (string, error) {
token, err := authManager.CreateNewToken(entityID, deviceID, tokenExpireTimeDuration)
return token, err
}
func (mm *ModuleManager) GetServerDomain() string {
return serverDomain
}

View File

@ -1,38 +0,0 @@
package core
import (
"errors"
"github.com/hashicorp/go-plugin"
)
type greeterServer struct {
Broker *plugin.MuxBroker
Module Module
}
// Server implmentation of go-plugin.plugin.Plugin.Server
func (p *ModuleRef) Server(b *plugin.MuxBroker) (interface{}, error) {
if p.F == nil {
return nil, errors.New("Greeter interface not implemeted")
}
return &greeterServer{Broker: b, Module: p.F()}, nil
}
// Name calls the plugin implementation to get the name of the plugin
func (p *greeterServer) Name(nothing interface{}, result *string) error {
*result = p.Module.Name()
return nil
}
// Version calls the plugin implementation to get the version of the plugin
func (p *greeterServer) Version(nothing interface{}, result *string) error {
*result = p.Module.Version()
return nil
}
// StartTime calls the plugin implementation to initialize plugin
func (p *greeterServer) Initialize(moduleAPI ModuleAPI, emptyResult interface{}) error {
p.Module.Initialize(moduleAPI)
return nil
}

View File

@ -1,49 +0,0 @@
package core
import (
"net/rpc"
"github.com/google/logger"
"github.com/hashicorp/go-plugin"
)
type moduleClient struct {
Broker *plugin.MuxBroker
Client *rpc.Client
}
// Client implmentation of go-plugin.plugin.Plugin.Client
func (p *ModuleRef) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) {
return &moduleClient{Broker: b, Client: c}, nil
}
// Name initiates an RPC call to the plugin name
func (p *moduleClient) Name() string {
var resp string
err := p.Client.Call("Plugin.Name", new(interface{}), &resp)
if err != nil {
logger.Fatal(err) // FIXME
}
return resp
}
// Version initiates an RPC call to the plugin version
func (p *moduleClient) Version() string {
var resp string
err := p.Client.Call("Plugin.Version", new(interface{}), &resp)
if err != nil {
logger.Fatal(err) // FIXME
}
return resp
}
// StartTime initiates an RPC call to the plugin for initializing
func (p *moduleClient) Initialize(moduleAPI ModuleAPI) {
var resp interface{}
err := p.Client.Call("Plugin.Initialize", map[string]interface{}{
"moduleAPI": moduleAPI,
}, &resp)
if err != nil {
logger.Fatal(err) // FIXME
}
}

View File

@ -1,17 +0,0 @@
package core
import (
"github.com/ChronosX88/zirconium/core/models"
"github.com/gorilla/websocket"
)
type OriginC2S struct {
wsConn *websocket.Conn
connID string
entityID *models.EntityID
deviceID *string
}
func (o *OriginC2S) Send(message models.BaseMessage) error {
return o.wsConn.WriteJSON(message)
}

View File

@ -1,56 +0,0 @@
package core
import (
"os"
"os/exec"
"path/filepath"
"github.com/google/logger"
"github.com/hashicorp/go-plugin"
)
type PluginManager struct{}
func NewPluginManager() *PluginManager {
return &PluginManager{}
}
func (p *PluginManager) StartPlugin(pluginsDirPath, pluginFile string, moduleManager ModuleAPI) error {
pluginsDirectory, _ := filepath.Abs(filepath.Dir(pluginsDirPath))
pluginFile = filepath.Join(pluginsDirectory, pluginFile)
logger.Info("Starting plugin: %s", pluginFile)
client := plugin.NewClient(&plugin.ClientConfig{
Cmd: exec.Command(pluginFile),
Managed: true,
SyncStdout: os.Stdout,
SyncStderr: os.Stderr,
HandshakeConfig: HandshakeConfig,
Plugins: GetPluginMap(nil),
})
rpcclient, err := client.Client()
if err != nil {
logger.Errorf("Failed to get RPC Client: %s", err)
client.Kill()
return err
}
// get the interface
raw, err := rpcclient.Dispense(ModuleInterfaceName)
if err != nil {
logger.Errorf("Failed to get interface: %s error: %s", ModuleInterfaceName, err)
return err
}
moduleObj := raw.(Module)
go func() {
moduleObj.Initialize(moduleManager)
}()
return nil
}

View File

@ -1,56 +1,43 @@
package core
import (
"github.com/ChronosX88/zirconium/core/models"
"github.com/cadmium-im/zirconium-go/core/models"
"github.com/google/logger"
)
type Router struct {
moduleManager *ModuleManager
connections []*OriginC2S
appContext *AppContext
handlers map[string][]C2SMessageHandler
connections []*Session
}
func NewRouter() (*Router, error) {
mm, err := NewModuleManager()
if err != nil {
return nil, err
}
type C2SMessageHandler interface {
HandleMessage(s *Session, message models.BaseMessage)
IsAuthorizationRequired() bool
HandlingType() string
}
func NewRouter(ctx *AppContext) (*Router, error) {
r := &Router{
moduleManager: mm.(*ModuleManager),
appContext: ctx,
handlers: map[string][]C2SMessageHandler{},
}
return r, nil
}
func (r *Router) RouteMessage(origin *OriginC2S, message models.BaseMessage) {
handlers := r.moduleManager.c2sMessageHandlers[message.MessageType]
func (r *Router) RouteMessage(origin *Session, message models.BaseMessage) {
handlers := r.handlers[message.MessageType]
if handlers != nil {
for _, v := range handlers {
if !v.AnonymousAllowed {
var entityID, deviceID string
var isValid bool
var err error
if message.AuthToken != "" {
isValid, entityID, deviceID, err = authManager.ValidateToken(message.AuthToken)
if err != nil || !isValid {
logger.Warningf("Connection %s isn't authorized", origin.connID)
msg := PrepareMessageUnauthorized(message)
origin.Send(msg)
}
} else {
if v.IsAuthorizationRequired() {
if len(origin.entityID) == 0 {
logger.Warningf("Connection %s isn't authorized", origin.connID)
msg := PrepareMessageUnauthorized(message)
origin.Send(msg)
}
if origin.entityID == nil {
origin.entityID = models.NewEntityID(entityID)
}
if origin.deviceID == nil {
origin.deviceID = &deviceID
msg := PrepareMessageUnauthorized(message, r.appContext.cfg.ServerDomains[0]) // fixme: domain
_ = origin.Send(msg)
}
}
go v.HandlerFunc(origin, message)
go v.HandleMessage(origin, message)
}
} else {
protocolError := models.ProtocolError{
@ -58,19 +45,12 @@ func (r *Router) RouteMessage(origin *OriginC2S, message models.BaseMessage) {
ErrText: "Server doesn't implement message type " + message.MessageType,
ErrPayload: make(map[string]interface{}),
}
errMsg := models.NewBaseMessage(message.ID, message.MessageType, serverDomain, message.From, false, StructToMap(protocolError))
errMsg := models.NewBaseMessage(message.ID, message.MessageType, r.appContext.cfg.ServerID, []string{message.From}, false, StructToMap(protocolError))
logger.Infof("Drop message with type %s because server hasn't proper handlers", message.MessageType)
origin.Send(errMsg)
_ = origin.Send(errMsg)
}
}
func (r *Router) RoutecoreEvent(sourceModuleName string, eventName string, eventPayload map[string]interface{}) {
handlers := r.moduleManager.coreEventHandlers[eventName]
if handlers != nil {
for _, v := range handlers {
go v(sourceModuleName, eventPayload)
}
} else {
logger.Infof("Drop event %s because server hasn't proper handlers", eventName)
}
func (r *Router) RegisterC2SHandler(c C2SMessageHandler) {
r.handlers[c.HandlingType()] = append(r.handlers[c.HandlingType()], c)
}

21
core/session.go Normal file
View File

@ -0,0 +1,21 @@
package core
import (
"github.com/cadmium-im/zirconium-go/core/models"
"github.com/gorilla/websocket"
)
type Session struct {
wsConn *websocket.Conn
connID string
entityID []*models.EntityID
deviceID *string
}
func (s *Session) Send(message models.BaseMessage) error {
return s.wsConn.WriteJSON(message)
}
func (s *Session) Close() error {
return s.wsConn.Close()
}

21
core/user_manager.go Normal file
View File

@ -0,0 +1,21 @@
package core
import "go.mongodb.org/mongo-driver/mongo"
const (
UsersCollectionName = "users"
)
type UserManager struct {
usersCol *mongo.Collection
}
func NewUserManager(db *mongo.Database) *UserManager {
col := db.Collection(UsersCollectionName)
um := &UserManager{
usersCol: col,
}
return um
}

View File

@ -2,12 +2,9 @@ package core
import (
"crypto/rand"
"log"
"reflect"
"github.com/ChronosX88/zirconium/core/models"
"github.com/google/logger"
"github.com/hashicorp/go-plugin"
"github.com/cadmium-im/zirconium-go/core/models"
)
func GenRandomBytes(size int) (blk []byte, err error) {
@ -42,58 +39,12 @@ func StructToMap(item interface{}) map[string]interface{} {
return res
}
func PrepareMessageUnauthorized(msg models.BaseMessage) models.BaseMessage {
func PrepareMessageUnauthorized(msg models.BaseMessage, serverDomain string) models.BaseMessage {
protocolError := models.ProtocolError{
ErrCode: "unauthorized",
ErrText: "Unauthorized access",
ErrPayload: make(map[string]interface{}),
}
errMsg := models.NewBaseMessage(msg.ID, msg.MessageType, serverDomain, msg.From, false, StructToMap(protocolError))
errMsg := models.NewBaseMessage(msg.ID, msg.MessageType, serverDomain, []string{msg.From}, false, StructToMap(protocolError))
return errMsg
}
var HandshakeConfig = plugin.HandshakeConfig{
ProtocolVersion: 1,
MagicCookieKey: "TEST_TEST",
MagicCookieValue: "qwerty",
}
type PluginOpts struct {
Module ModuleFunc
RunAsPlugin bool
}
// GetPluginMap returns the plugin map defined Hashicorp go-plugin.
// The reserved parameter should only be used by the RPC receiver (the plugin).
// Otherwise, reserved should be nil for the RPC sender (the mainapp).
func GetPluginMap(reserved *PluginOpts) map[string]plugin.Plugin {
var moduleObj ModuleRef
if reserved != nil {
moduleObj.F = reserved.Module
}
return map[string]plugin.Plugin{
ModuleInterfaceName: &moduleObj,
}
}
func StartPlugin(opts *PluginOpts, quit chan bool) {
if opts.RunAsPlugin {
go func() {
logger.Info("Starting plugin communication...")
plugin.Serve(&plugin.ServeConfig{
HandshakeConfig: HandshakeConfig,
Plugins: GetPluginMap(opts),
})
logger.Info("Exiting plugin communication...")
quit <- true
logger.Info("Exiting plugin...")
}()
} else {
log.Println("Starting in standalone mode...")
}
}

49
core/websocket_server.go Normal file
View File

@ -0,0 +1,49 @@
package core
import (
"fmt"
"github.com/google/logger"
"github.com/gorilla/mux"
"github.com/gorilla/websocket"
"net/http"
)
var wsUpgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
type WebsocketServer struct {
r *mux.Router
connHandler *ConnectionHandler
cfg *Config
}
func NewWebsocketServer(cfg *Config, connHandler *ConnectionHandler) *WebsocketServer {
wss := &WebsocketServer{}
wss.connHandler = connHandler
wss.cfg = cfg
r := mux.NewRouter()
wss.r = r
r.HandleFunc("/", func(response http.ResponseWriter, request *http.Request) {
_, _ = response.Write([]byte("Zirconium server is up and running!"))
}).Methods("GET")
r.HandleFunc(cfg.Websocket.Endpoint, func(w http.ResponseWriter, r *http.Request) {
ws, err := wsUpgrader.Upgrade(w, r, nil)
if err != nil {
logger.Errorf(err.Error())
return
}
wss.connHandler.HandleNewConnection(ws)
})
return wss
}
func (wss *WebsocketServer) Run() error {
addr := fmt.Sprintf("%s:%d", wss.cfg.Websocket.Host, wss.cfg.Websocket.Port)
return http.ListenAndServe(addr, wss.r)
}

7
go.mod
View File

@ -1,13 +1,14 @@
module github.com/ChronosX88/zirconium
module github.com/cadmium-im/zirconium-go
go 1.13
require (
github.com/BurntSushi/toml v0.3.1
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/google/logger v1.0.1
github.com/google/uuid v1.1.1
github.com/gorilla/mux v1.7.3
github.com/gorilla/websocket v1.4.1
github.com/hashicorp/go-plugin v1.0.1
github.com/pelletier/go-toml v1.6.0
github.com/pelletier/go-toml v1.7.0
go.mongodb.org/mongo-driver v1.5.1
)

151
go.sum
View File

@ -1,14 +1,43 @@
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/aws/aws-sdk-go v1.34.28 h1:sscPpn/Ns3i0F4HPEWAVcwdIRaZZCuL7llJ2/60yPIk=
github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=
github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs=
github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk=
github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28=
github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo=
github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk=
github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw=
github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360=
github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg=
github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE=
github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8=
github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=
github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=
github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/logger v1.0.1 h1:Jtq7/44yDwUXMaLTYgXFC31zpm6Oku7OI/k4//yVANQ=
github.com/google/logger v1.0.1/go.mod h1:w7O8nrRr0xufejBlQMI83MXqRusvREoJdaAxV+CoAB4=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
@ -17,37 +46,97 @@ github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd h1:rNuUHR+CvK1IS89MMtcF0EpcVMZtjKfPRp4MEmt/aTs=
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
github.com/hashicorp/go-plugin v1.0.1 h1:4OtAfUGbnKC6yS48p0CtMX2oFYtzFZVv6rok3cRWgnE=
github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 h1:7GoSOOW2jpsfkntVKaS2rAr1TJqfcxotyaUcuxoZSzg=
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4=
github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4=
github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
github.com/klauspost/compress v1.9.5 h1:U+CaK85mrNNb4k8BNOfgJtJ/gr6kswUCFj6miSzVC6M=
github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI=
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d h1:g9qWBGx4puODJTMVyoPrpoxPFgVGd+z1DZwjfRu4d0I=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.0.2 h1:akYIkZ28e6A96dkWNJQu3nmCzH3YfwMPQExUYDaRv7w=
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
github.com/xdg-go/stringprep v1.0.2 h1:6iq84/ryjjeRmMJwxutI51F2GIPlP5BfTvXHeYjyhBc=
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
go.mongodb.org/mongo-driver v1.5.1 h1:9nOVLGDfOaZ9R0tBumx/BcuqkbFpyTCU2r/Po7A2azI=
go.mongodb.org/mongo-driver v1.5.1/go.mod h1:gRXCHX4Jo7J0IJ1oDQyUxF7jfy19UfxniMS4xxMmUqw=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2 h1:T5DasATyLQfmbTpfEXx/IOL9vfjzW6up+ZDkmHvIf2s=
golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/grpc v1.14.0 h1:ArxJuB1NWfPY6r9Gp9gqwplT0Ge7nqv9msgu03lHLmo=
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File