diff --git a/constants/constants.go b/constants/constants.go new file mode 100644 index 0000000..7b46c64 --- /dev/null +++ b/constants/constants.go @@ -0,0 +1,5 @@ +package constants + +const ( + DefaultMixPort = "1789" +) diff --git a/docs/docs.go b/docs/docs.go index fe5f73f..ac1781c 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -1,14 +1,19 @@ // GENERATED BY THE COMMAND ABOVE; DO NOT EDIT // This file was generated by swaggo/swag at -// 2019-09-18 13:34:09.321106544 +0100 BST m=+0.021854677 +// 2019-09-18 14:51:50.255767945 +0100 BST m=+0.021395519 package docs import ( + "bytes" + "encoding/json" + + "github.com/alecthomas/template" "github.com/swaggo/swag" ) var doc = `{ + "schemes": {{ marshal .Schemes }}, "swagger": "2.0", "info": { "description": "This is a temporarily centralized directory/PKI/metrics API to allow us to get the other Nym node types running. Its functionality will eventually be folded into other parts of Nym.", @@ -21,6 +26,8 @@ var doc = `{ }, "version": "1.0" }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", "paths": { "/api/healthcheck": { "get": { @@ -354,7 +361,6 @@ var doc = `{ "models.HostInfo": { "type": "object", "required": [ - "host", "pubKey" ], "properties": { @@ -369,9 +375,8 @@ var doc = `{ "models.MixHostInfo": { "type": "object", "required": [ - "pubKey", "layer", - "host" + "pubKey" ], "properties": { "host": { @@ -408,7 +413,6 @@ var doc = `{ "models.MixProviderHostInfo": { "type": "object", "required": [ - "host", "pubKey" ], "properties": { @@ -454,11 +458,39 @@ var doc = `{ } }` +type swaggerInfo struct { + Version string + Host string + BasePath string + Schemes []string + Title string + Description string +} + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = swaggerInfo{ Schemes: []string{}} + type s struct{} func (s *s) ReadDoc() string { - return doc + t, err := template.New("swagger_info").Funcs(template.FuncMap{ + "marshal": func(v interface {}) string { + a, _ := json.Marshal(v) + return string(a) + }, + }).Parse(doc) + if err != nil { + return doc + } + + var tpl bytes.Buffer + if err := t.Execute(&tpl, SwaggerInfo); err != nil { + return doc + } + + return tpl.String() } + func init() { swag.Register(swag.Name, &s{}) } diff --git a/docs/swagger.json b/docs/swagger.json new file mode 100644 index 0000000..8c90fe4 --- /dev/null +++ b/docs/swagger.json @@ -0,0 +1,444 @@ +{ + "swagger": "2.0", + "info": { + "description": "This is a temporarily centralized directory/PKI/metrics API to allow us to get the other Nym node types running. Its functionality will eventually be folded into other parts of Nym.", + "title": "Nym Directory API", + "termsOfService": "http://swagger.io/terms/", + "contact": {}, + "license": { + "name": "Apache 2.0", + "url": "https://github.com/nymtech/directory-server/license" + }, + "version": "1.0" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/api/healthcheck": { + "get": { + "description": "Returns a 200 if the directory server is available.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "healthcheck" + ], + "summary": "Lets the directory server tell the world it's alive", + "operationId": "healthCheck", + "responses": { + "200": {} + } + } + }, + "/api/metrics/mixes": { + "get": { + "description": "You'd never want to run this in production, but for demo and debug purposes it gives us the ability to generate useful visualisations of network traffic.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "metrics" + ], + "summary": "Lists mixnode activity in the past 1 second", + "operationId": "listMixMetrics", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/models.MixMetric" + } + } + }, + "400": { + "description": "Bad Request", + "schema": { + "type": "object", + "$ref": "#/definitions/models.Error" + } + }, + "404": { + "description": "Not Found", + "schema": { + "type": "object", + "$ref": "#/definitions/models.Error" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "type": "object", + "$ref": "#/definitions/models.Error" + } + } + } + }, + "post": { + "description": "You'd never want to run this in production, but for demo and debug purposes it gives us the ability to generate useful visualisations of network traffic.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "metrics" + ], + "summary": "Create a metric detailing how many messages a given mixnode sent and received", + "operationId": "createMixMetric", + "parameters": [ + { + "description": "object", + "name": "object", + "in": "body", + "required": true, + "schema": { + "type": "object", + "$ref": "#/definitions/models.MixMetric" + } + } + ], + "responses": { + "201": {}, + "400": { + "description": "Bad Request", + "schema": { + "type": "object", + "$ref": "#/definitions/models.Error" + } + }, + "404": { + "description": "Not Found", + "schema": { + "type": "object", + "$ref": "#/definitions/models.Error" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "type": "object", + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/api/presence/coconodes": { + "post": { + "description": "Nym Coconut nodes can ping this method to let the directory server know they're up. We can then use this info to create topologies of the overall Nym network.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "presence" + ], + "summary": "Lets a coconut node tell the directory server it's alive", + "operationId": "addCocoNode", + "parameters": [ + { + "description": "object", + "name": "object", + "in": "body", + "required": true, + "schema": { + "type": "object", + "$ref": "#/definitions/models.HostInfo" + } + } + ], + "responses": { + "201": {}, + "400": { + "description": "Bad Request", + "schema": { + "type": "object", + "$ref": "#/definitions/models.Error" + } + }, + "404": { + "description": "Not Found", + "schema": { + "type": "object", + "$ref": "#/definitions/models.Error" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "type": "object", + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/api/presence/mixnodes": { + "post": { + "description": "Nym mixnodes can ping this method to let the directory server know they're up. We can then use this info to create topologies of the overall Nym network.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "presence" + ], + "summary": "Lets mixnode a node tell the directory server it's alive", + "operationId": "addMixNode", + "parameters": [ + { + "description": "object", + "name": "object", + "in": "body", + "required": true, + "schema": { + "type": "object", + "$ref": "#/definitions/models.MixHostInfo" + } + } + ], + "responses": { + "201": {}, + "400": { + "description": "Bad Request", + "schema": { + "type": "object", + "$ref": "#/definitions/models.Error" + } + }, + "404": { + "description": "Not Found", + "schema": { + "type": "object", + "$ref": "#/definitions/models.Error" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "type": "object", + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/api/presence/providers": { + "post": { + "description": "Nym mix providers can ping this method to let the directory server know they're up. We can then use this info to create topologies of the overall Nym network.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "presence" + ], + "summary": "Lets a mixnode tell the directory server it's alive", + "operationId": "addMixProvider", + "parameters": [ + { + "description": "object", + "name": "object", + "in": "body", + "required": true, + "schema": { + "type": "object", + "$ref": "#/definitions/models.MixProviderHostInfo" + } + } + ], + "responses": { + "201": {}, + "400": { + "description": "Bad Request", + "schema": { + "type": "object", + "$ref": "#/definitions/models.Error" + } + }, + "404": { + "description": "Not Found", + "schema": { + "type": "object", + "$ref": "#/definitions/models.Error" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "type": "object", + "$ref": "#/definitions/models.Error" + } + } + } + } + }, + "/api/presence/topology": { + "get": { + "description": "Nym nodes periodically ping the directory server to register that they're alive. This method provides a list of nodes which have been most recently seen.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "presence" + ], + "summary": "Lists which Nym mixnodes, providers, and coconodes are alive", + "operationId": "topology", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "object", + "$ref": "#/definitions/models.Topology" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "type": "object", + "$ref": "#/definitions/models.Error" + } + }, + "404": { + "description": "Not Found", + "schema": { + "type": "object", + "$ref": "#/definitions/models.Error" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "type": "object", + "$ref": "#/definitions/models.Error" + } + } + } + } + } + }, + "definitions": { + "models.Error": { + "type": "object", + "properties": { + "error": { + "type": "string" + } + } + }, + "models.HostInfo": { + "type": "object", + "required": [ + "pubKey" + ], + "properties": { + "host": { + "type": "string" + }, + "pubKey": { + "type": "string" + } + } + }, + "models.MixHostInfo": { + "type": "object", + "required": [ + "layer", + "pubKey" + ], + "properties": { + "host": { + "type": "string" + }, + "layer": { + "type": "integer" + }, + "pubKey": { + "type": "string" + } + } + }, + "models.MixMetric": { + "type": "object", + "required": [ + "pubKey" + ], + "properties": { + "pubKey": { + "type": "string" + }, + "received": { + "type": "integer" + }, + "sent": { + "type": "object", + "required": [ + "sent" + ] + } + } + }, + "models.MixProviderHostInfo": { + "type": "object", + "required": [ + "pubKey" + ], + "properties": { + "host": { + "type": "string" + }, + "pubKey": { + "type": "string" + }, + "registeredClients": { + "type": "array", + "items": { + "$ref": "#/definitions/models.RegisteredClient" + } + } + } + }, + "models.RegisteredClient": { + "type": "object", + "required": [ + "pubKey" + ], + "properties": { + "pubKey": { + "type": "string" + } + } + }, + "models.Topology": { + "type": "object", + "properties": { + "cocoNodes": { + "type": "object" + }, + "mixNodes": { + "type": "object" + }, + "mixProviderNodes": { + "type": "object" + } + } + } + } +} \ No newline at end of file diff --git a/docs/swagger.yaml b/docs/swagger.yaml new file mode 100644 index 0000000..5564ce7 --- /dev/null +++ b/docs/swagger.yaml @@ -0,0 +1,318 @@ +basePath: '{{.BasePath}}' +definitions: + models.Error: + properties: + error: + type: string + type: object + models.HostInfo: + properties: + host: + type: string + pubKey: + type: string + required: + - pubKey + type: object + models.MixHostInfo: + properties: + host: + type: string + layer: + type: integer + pubKey: + type: string + required: + - layer + - pubKey + type: object + models.MixMetric: + properties: + pubKey: + type: string + received: + type: integer + sent: + required: + - sent + type: object + required: + - pubKey + type: object + models.MixProviderHostInfo: + properties: + host: + type: string + pubKey: + type: string + registeredClients: + items: + $ref: '#/definitions/models.RegisteredClient' + type: array + required: + - pubKey + type: object + models.RegisteredClient: + properties: + pubKey: + type: string + required: + - pubKey + type: object + models.Topology: + properties: + cocoNodes: + type: object + mixNodes: + type: object + mixProviderNodes: + type: object + type: object +host: '{{.Host}}' +info: + contact: {} + description: This is a temporarily centralized directory/PKI/metrics API to allow + us to get the other Nym node types running. Its functionality will eventually + be folded into other parts of Nym. + license: + name: Apache 2.0 + url: https://github.com/nymtech/directory-server/license + termsOfService: http://swagger.io/terms/ + title: Nym Directory API + version: "1.0" +paths: + /api/healthcheck: + get: + consumes: + - application/json + description: Returns a 200 if the directory server is available. + operationId: healthCheck + produces: + - application/json + responses: + "200": {} + summary: Lets the directory server tell the world it's alive + tags: + - healthcheck + /api/metrics/mixes: + get: + consumes: + - application/json + description: You'd never want to run this in production, but for demo and debug + purposes it gives us the ability to generate useful visualisations of network + traffic. + operationId: listMixMetrics + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + $ref: '#/definitions/models.MixMetric' + type: array + "400": + description: Bad Request + schema: + $ref: '#/definitions/models.Error' + type: object + "404": + description: Not Found + schema: + $ref: '#/definitions/models.Error' + type: object + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/models.Error' + type: object + summary: Lists mixnode activity in the past 1 second + tags: + - metrics + post: + consumes: + - application/json + description: You'd never want to run this in production, but for demo and debug + purposes it gives us the ability to generate useful visualisations of network + traffic. + operationId: createMixMetric + parameters: + - description: object + in: body + name: object + required: true + schema: + $ref: '#/definitions/models.MixMetric' + type: object + produces: + - application/json + responses: + "201": {} + "400": + description: Bad Request + schema: + $ref: '#/definitions/models.Error' + type: object + "404": + description: Not Found + schema: + $ref: '#/definitions/models.Error' + type: object + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/models.Error' + type: object + summary: Create a metric detailing how many messages a given mixnode sent and + received + tags: + - metrics + /api/presence/coconodes: + post: + consumes: + - application/json + description: Nym Coconut nodes can ping this method to let the directory server + know they're up. We can then use this info to create topologies of the overall + Nym network. + operationId: addCocoNode + parameters: + - description: object + in: body + name: object + required: true + schema: + $ref: '#/definitions/models.HostInfo' + type: object + produces: + - application/json + responses: + "201": {} + "400": + description: Bad Request + schema: + $ref: '#/definitions/models.Error' + type: object + "404": + description: Not Found + schema: + $ref: '#/definitions/models.Error' + type: object + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/models.Error' + type: object + summary: Lets a coconut node tell the directory server it's alive + tags: + - presence + /api/presence/mixnodes: + post: + consumes: + - application/json + description: Nym mixnodes can ping this method to let the directory server know + they're up. We can then use this info to create topologies of the overall + Nym network. + operationId: addMixNode + parameters: + - description: object + in: body + name: object + required: true + schema: + $ref: '#/definitions/models.MixHostInfo' + type: object + produces: + - application/json + responses: + "201": {} + "400": + description: Bad Request + schema: + $ref: '#/definitions/models.Error' + type: object + "404": + description: Not Found + schema: + $ref: '#/definitions/models.Error' + type: object + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/models.Error' + type: object + summary: Lets mixnode a node tell the directory server it's alive + tags: + - presence + /api/presence/providers: + post: + consumes: + - application/json + description: Nym mix providers can ping this method to let the directory server + know they're up. We can then use this info to create topologies of the overall + Nym network. + operationId: addMixProvider + parameters: + - description: object + in: body + name: object + required: true + schema: + $ref: '#/definitions/models.MixProviderHostInfo' + type: object + produces: + - application/json + responses: + "201": {} + "400": + description: Bad Request + schema: + $ref: '#/definitions/models.Error' + type: object + "404": + description: Not Found + schema: + $ref: '#/definitions/models.Error' + type: object + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/models.Error' + type: object + summary: Lets a mixnode tell the directory server it's alive + tags: + - presence + /api/presence/topology: + get: + consumes: + - application/json + description: Nym nodes periodically ping the directory server to register that + they're alive. This method provides a list of nodes which have been most recently + seen. + operationId: topology + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/models.Topology' + type: object + "400": + description: Bad Request + schema: + $ref: '#/definitions/models.Error' + type: object + "404": + description: Not Found + schema: + $ref: '#/definitions/models.Error' + type: object + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/models.Error' + type: object + summary: Lists which Nym mixnodes, providers, and coconodes are alive + tags: + - presence +swagger: "2.0" diff --git a/go.mod b/go.mod index 8704953..db44d03 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.12 require ( github.com/BorisBorshevsky/timemock v0.0.0-20180501151413-a469e345aaba + github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 github.com/coreos/etcd v3.3.10+incompatible github.com/dgraph-io/badger v1.6.0 github.com/ethereum/go-ethereum v1.9.3 // indirect diff --git a/go.sum b/go.sum index d39acba..5062a98 100644 --- a/go.sum +++ b/go.sum @@ -11,6 +11,8 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/coreos/etcd v3.3.10+incompatible h1:jFneRYjIvLMLhDLCzuTuU4rSJUjRplcJQ7pD7MnhC04= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= diff --git a/models/presence.go b/models/presence.go index dafd8eb..f56dac2 100644 --- a/models/presence.go +++ b/models/presence.go @@ -2,7 +2,7 @@ package models // HostInfo comes from a node telling us it's alive type HostInfo struct { - Host string `json:"host" binding:"required"` + Host string `json:"host"` PubKey string `json:"pubKey" binding:"required"` } diff --git a/presence/controller.go b/presence/controller.go index 9205da2..66b0907 100644 --- a/presence/controller.go +++ b/presence/controller.go @@ -1,9 +1,11 @@ package presence import ( + "net" "net/http" "github.com/gin-gonic/gin" + "github.com/nymtech/directory-server/constants" "github.com/nymtech/directory-server/models" ) @@ -53,6 +55,7 @@ func (controller *controller) AddMixNodePresence(c *gin.Context) { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } + json.HostInfo.Host = net.JoinHostPort(c.ClientIP(), constants.DefaultMixPort) controller.service.AddMixNodePresence(json) c.JSON(http.StatusCreated, gin.H{"ok": true}) } @@ -99,6 +102,7 @@ func (controller *controller) AddMixProviderPresence(c *gin.Context) { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } + json.HostInfo.Host = net.JoinHostPort(c.ClientIP(), constants.DefaultMixPort) controller.service.AddMixProviderPresence(json) c.JSON(http.StatusCreated, gin.H{"ok": true}) }