From c00a4da2181142fe3ad1cad2e7d207f7964880cf Mon Sep 17 00:00:00 2001 From: Florimond Husquinet Date: Mon, 14 Oct 2024 11:03:15 +0200 Subject: [PATCH] [ADD] cli: keygen command (#433) --- go.mod | 13 +++-- go.sum | 14 +++++ internal/command/keygen/keygen.go | 89 +++++++++++++++++++++++++++++++ main.go | 2 + 4 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 internal/command/keygen/keygen.go diff --git a/go.mod b/go.mod index 8b3a2b5b..f58c4fab 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/emitter-io/config v1.0.0 github.com/emitter-io/stats v1.0.3 github.com/golang/snappy v0.0.4 - github.com/gorilla/websocket v1.5.1 + github.com/gorilla/websocket v1.5.3 github.com/jawher/mow.cli v1.2.0 github.com/kelindar/binary v1.0.18 github.com/kelindar/rate v1.0.0 @@ -25,11 +25,13 @@ require ( github.com/tidwall/pretty v1.2.1 // indirect github.com/valyala/fasthttp v1.51.0 github.com/weaveworks/mesh v0.0.0-20191105120815-58dbcc3e8e63 - golang.org/x/crypto v0.18.0 - golang.org/x/net v0.20.0 // indirect + golang.org/x/crypto v0.25.0 + golang.org/x/net v0.27.0 // indirect gopkg.in/alexcesaro/statsd.v2 v2.0.0 ) +require github.com/eclipse/paho.mqtt.golang v1.5.0 + require ( github.com/andybalholm/brotli v1.1.0 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -60,8 +62,9 @@ require ( github.com/tidwall/tinyqueue v0.1.1 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect go.opencensus.io v0.24.0 // indirect - golang.org/x/sys v0.16.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/text v0.16.0 // indirect google.golang.org/protobuf v1.32.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index d761fab9..72b5a6ef 100644 --- a/go.sum +++ b/go.sum @@ -45,6 +45,8 @@ github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140/go.mod h1:c9O8+fp github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/eclipse/paho.mqtt.golang v1.5.0 h1:EH+bUVJNgttidWFkLLVKaQPGmkTUfQQqjOsyvMGvD6o= +github.com/eclipse/paho.mqtt.golang v1.5.0/go.mod h1:du/2qNQVqJf/Sqs4MEL77kR8QTqANF7XU7Fk0aOTAgk= github.com/emitter-io/address v1.0.1 h1:1bTyviCKDkB60rrFpHr6BY3AKjNWP3InY/WO6qPKkVU= github.com/emitter-io/address v1.0.1/go.mod h1:kF9+NdGTAvzRKMd78zjj7MN01yDB9fPwZl2waJRlfYU= github.com/emitter-io/config v1.0.0 h1:qpJMei4v3KL0Z5vsspVful/JIRr6v4zg8R28pG4Ry4M= @@ -100,6 +102,8 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/gopherjs/gopherjs v0.0.0-20200209183636-89e6cbcd0b6d/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -224,6 +228,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -242,6 +248,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -249,6 +257,8 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -259,10 +269,14 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= diff --git a/internal/command/keygen/keygen.go b/internal/command/keygen/keygen.go new file mode 100644 index 00000000..886604cf --- /dev/null +++ b/internal/command/keygen/keygen.go @@ -0,0 +1,89 @@ +/********************************************************************************** +* Copyright (c) 2009-2019 Misakai Ltd. +* 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. +************************************************************************************/ + +package keygen + +import ( + "encoding/json" + "fmt" + + mqtt "github.com/eclipse/paho.mqtt.golang" + "github.com/emitter-io/emitter/internal/errors" + "github.com/emitter-io/emitter/internal/provider/logging" + "github.com/emitter-io/emitter/internal/service/keygen" + cli "github.com/jawher/mow.cli" +) + +// Generate a new channel key. +func NewKey(cmd *cli.Cmd) { + cmd.Spec = "MASTERKEY CHANNEL ACCESS [ -t=] [ -h= ]" + var ( + masterkey = cmd.StringArg("MASTERKEY", "", "Specifies the master key for generating channel keys.") + channel = cmd.StringArg("CHANNEL", "", "Specifies the name channel for which to generate key.") + access = cmd.StringArg("ACCESS", "", "Specifies the access rights for the channel (rwslpex).") + ttl = cmd.IntOpt("t ttl", 0, "Specifies the time to live for the key in seconds. By default, the key will never expire.") + host = cmd.StringOpt("h host", "127.0.0.1:8080", "Specifies the broker host name and port. This must follow the format.") + ) + + cmd.Action = func() { + // Create a channel to receive the response. + respChan := make(chan []byte) + + // Create a new MQTT client. + opts := mqtt.NewClientOptions().AddBroker(fmt.Sprintf("tcp://%s", *host)) + opts.SetDefaultPublishHandler(func(client mqtt.Client, m mqtt.Message) { + respChan <- m.Payload() + }) + client := mqtt.NewClient(opts) + + // Connect to the MQTT broker. + if token := client.Connect(); token.Wait() && token.Error() != nil { + panic(fmt.Errorf("failed to connect: %v", token.Error())) + } + + // Publish the request. + request := keygen.Request{ + Key: *masterkey, + Channel: *channel, + Type: *access, + TTL: int32(*ttl), + } + payload, err := json.Marshal(request) + if err != nil { + logging.LogError("keygen", "marshaling the request", err) + return + } + if token := client.Publish("emitter/keygen/", 1, false, payload); token.Wait() && token.Error() != nil { + logging.LogError("keygen", "publishing the request", token.Error()) + return + } + + // Wait for the response and check whether it's an error. + response := <-respChan + var errResponse errors.Error + if err := json.Unmarshal(response, &errResponse); err == nil && errResponse.Error() != "" { + logging.LogError("keygen", "generating the key", fmt.Errorf("error: %s", errResponse.Error())) + return + } + + // Parse the response and print the key. + keygen := keygen.Response{} + if err := json.Unmarshal(response, &keygen); err != nil { + logging.LogError("keygen", "parsing the response", err) + return + } + fmt.Println(keygen.Key) + client.Disconnect(250) + } +} diff --git a/main.go b/main.go index c982ef8c..5fb78683 100644 --- a/main.go +++ b/main.go @@ -21,6 +21,7 @@ import ( "github.com/emitter-io/config/dynamo" "github.com/emitter-io/config/vault" "github.com/emitter-io/emitter/internal/broker" + "github.com/emitter-io/emitter/internal/command/keygen" "github.com/emitter-io/emitter/internal/command/license" "github.com/emitter-io/emitter/internal/command/load" "github.com/emitter-io/emitter/internal/command/version" @@ -44,6 +45,7 @@ func main() { cmd.Command("new", "Generates a new license and secret key pair.", license.New) // TODO: add more sub-commands for license }) + app.Command("keygen", "Generates a new key for a channel.", keygen.NewKey) app.Run(os.Args) }