From 3f87401d490e0a94dcb0e8bee49a4fa57d93af66 Mon Sep 17 00:00:00 2001 From: Harvey Kandola Date: Wed, 22 Feb 2017 20:03:40 -0800 Subject: [PATCH] support for license keys --- app/app/components/global-settings.js | 19 ++- app/app/pods/customize/global/controller.js | 12 +- app/app/pods/customize/global/route.js | 3 +- app/app/pods/customize/global/template.hbs | 2 +- app/app/services/global.js | 35 ++++- .../templates/components/global-settings.hbs | 32 +++-- core/api/endpoint/global_endpoint.go | 123 +++++++++++++++++- core/api/endpoint/router.go | 6 +- core/api/endpoint/server.go | 3 + core/product.go | 52 +++++++- 10 files changed, 252 insertions(+), 35 deletions(-) diff --git a/app/app/components/global-settings.js b/app/app/components/global-settings.js index 405d4ced..cadea72f 100644 --- a/app/app/components/global-settings.js +++ b/app/app/components/global-settings.js @@ -16,14 +16,14 @@ const { } = Ember; export default Ember.Component.extend({ - SMTPHostEmptyError: computed.empty('model.global.host'), - SMTPPortEmptyError: computed.empty('model.global.port'), - SMTPSenderEmptyError: computed.empty('model.global.sender'), - SMTPUserIdEmptyError: computed.empty('model.global.userid'), - SMTPPasswordEmptyError: computed.empty('model.global.password'), + SMTPHostEmptyError: computed.empty('model.smtp.host'), + SMTPPortEmptyError: computed.empty('model.smtp.port'), + SMTPSenderEmptyError: computed.empty('model.smtp.sender'), + SMTPUserIdEmptyError: computed.empty('model.smtp.userid'), + SMTPPasswordEmptyError: computed.empty('model.smtp.password'), actions: { - save() { + saveSMTP() { if (this.get('SMTPHostEmptyError')) { $("#smtp-host").focus(); return; @@ -45,7 +45,12 @@ export default Ember.Component.extend({ return; } - this.get('save')().then(() => { + this.get('saveSMTP')().then(() => { + }); + }, + + saveLicense() { + this.get('saveLicense')().then(() => { }); } } diff --git a/app/app/pods/customize/global/controller.js b/app/app/pods/customize/global/controller.js index 499377a2..e94bfb61 100644 --- a/app/app/pods/customize/global/controller.js +++ b/app/app/pods/customize/global/controller.js @@ -16,9 +16,17 @@ export default Ember.Controller.extend(NotifierMixin, { global: Ember.inject.service(), actions: { - save() { + saveSMTP() { if(this.get('session.isGlobalAdmin')) { - return this.get('global').saveConfig(this.model.global).then(() => { + return this.get('global').saveSMTPConfig(this.model.smtp).then(() => { + this.showNotification('Saved'); + }); + } + }, + + saveLicense() { + if(this.get('session.isGlobalAdmin')) { + return this.get('global').saveLicense(this.model.license).then(() => { this.showNotification('Saved'); }); } diff --git a/app/app/pods/customize/global/route.js b/app/app/pods/customize/global/route.js index 57701fc0..396dce26 100644 --- a/app/app/pods/customize/global/route.js +++ b/app/app/pods/customize/global/route.js @@ -26,7 +26,8 @@ export default Ember.Route.extend(AuthenticatedRouteMixin, { model() { return RSVP.hash({ - global: this.get('global').getConfig() + smtp: this.get('global').getSMTPConfig(), + license: this.get('global').getLicense() }); }, diff --git a/app/app/pods/customize/global/template.hbs b/app/app/pods/customize/global/template.hbs index bdf3d052..0ea61f38 100644 --- a/app/app/pods/customize/global/template.hbs +++ b/app/app/pods/customize/global/template.hbs @@ -1 +1 @@ -{{global-settings model=model save=(action 'save')}} +{{global-settings model=model saveSMTP=(action 'saveSMTP') saveLicense=(action 'saveLicense')}} diff --git a/app/app/services/global.js b/app/app/services/global.js index 2a37875a..830690cc 100644 --- a/app/app/services/global.js +++ b/app/app/services/global.js @@ -21,10 +21,10 @@ export default Ember.Service.extend({ appMeta: service(), store: service(), - // Returns global configuration. - getConfig() { + // Returns SMTP configuration. + getSMTPConfig() { if(this.get('sessionService.isGlobalAdmin')) { - return this.get('ajax').request(`global`, { + return this.get('ajax').request(`global/smtp`, { method: 'GET' }).then((response) => { return response; @@ -32,13 +32,36 @@ export default Ember.Service.extend({ } }, - // Saves global configuration. - saveConfig(config) { + // Saves SMTP configuration. + saveSMTPConfig(config) { if(this.get('sessionService.isGlobalAdmin')) { - return this.get('ajax').request(`global`, { + return this.get('ajax').request(`global/smtp`, { method: 'PUT', data: JSON.stringify(config) }); } + }, + + // Returns product license. + getLicense() { + if(this.get('sessionService.isGlobalAdmin')) { + return this.get('ajax').request(`global/license`, { + method: 'GET', + dataType: "text" + }).then((response) => { + return response; + }); + } + }, + + // Saves product license + saveLicense(license) { + if(this.get('sessionService.isGlobalAdmin')) { + return this.get('ajax').request(`global/license`, { + method: 'PUT', + dataType: 'text', + data: license + }); + } } }); diff --git a/app/app/templates/components/global-settings.hbs b/app/app/templates/components/global-settings.hbs index 06375426..28146c08 100644 --- a/app/app/templates/components/global-settings.hbs +++ b/app/app/templates/components/global-settings.hbs @@ -1,32 +1,48 @@
-
Global Settings
-
Settings applicable for all tenants
+
Mail Server Settings
+
Used for sending email notifications
e.g. my.host.com
- {{focus-input id="smtp-host" type="text" value=model.global.host class=(if SMTPHostEmptyError 'error')}} + {{focus-input id="smtp-host" type="text" value=model.smtp.host class=(if SMTPHostEmptyError 'error')}}
e.g. 587
- {{input id="smtp-port" type="text" value=model.global.port class=(if SMTPPortEmptyError 'error')}} + {{input id="smtp-port" type="text" value=model.smtp.port class=(if SMTPPortEmptyError 'error')}}
e.g. noreply@documize.com
- {{input id="smtp-sender" type="text" value=model.global.sender class=(if SMTPSenderEmptyError 'error')}} + {{input id="smtp-sender" type="text" value=model.smtp.sender class=(if SMTPSenderEmptyError 'error')}}
Your credentials
- {{input id="smtp-userid" type="text" value=model.global.userid class=(if SMTPUserIdEmptyError 'error')}} + {{input id="smtp-userid" type="text" value=model.smtp.userid class=(if SMTPUserIdEmptyError 'error')}}
Your credentials
- {{input id="smtp-password" type="text" value=model.global.password class=(if SMTPPasswordEmptyError 'error')}} + {{input id="smtp-password" type="text" value=model.smtp.password class=(if SMTPPasswordEmptyError 'error')}}
-
save
+
save
+
+ +
+
+ +
+
+
Edition License
+
Product license
+
+
+ +
Please provide valid XML
+ {{textarea value=model.license rows="5"}} +
+
save
diff --git a/core/api/endpoint/global_endpoint.go b/core/api/endpoint/global_endpoint.go index 2f397ba6..94bcae17 100644 --- a/core/api/endpoint/global_endpoint.go +++ b/core/api/endpoint/global_endpoint.go @@ -16,13 +16,15 @@ import ( "io/ioutil" "net/http" + "encoding/xml" + "fmt" "github.com/documize/community/core/api/request" "github.com/documize/community/core/api/util" ) -// GetGlobalConfig returns installation-wide settings -func GetGlobalConfig(w http.ResponseWriter, r *http.Request) { - method := "GetGlobalConfig" +// GetSMTPConfig returns installation-wide SMTP settings +func GetSMTPConfig(w http.ResponseWriter, r *http.Request) { + method := "GetSMTPConfig" p := request.GetPersister(r) if !p.Context.Global { @@ -39,16 +41,16 @@ func GetGlobalConfig(w http.ResponseWriter, r *http.Request) { json, err := json.Marshal(y) if err != nil { - writeJSONMarshalError(w, method, "GetGlobalConfig", err) + writeJSONMarshalError(w, method, "SMTP", err) return } util.WriteSuccessBytes(w, json) } -// SaveGlobalConfig persists global configuration. -func SaveGlobalConfig(w http.ResponseWriter, r *http.Request) { - method := "SaveGlobalConfig" +// SaveSMTPConfig persists global SMTP configuration. +func SaveSMTPConfig(w http.ResponseWriter, r *http.Request) { + method := "SaveSMTPConfig" p := request.GetPersister(r) if !p.Context.Global { @@ -79,3 +81,110 @@ func SaveGlobalConfig(w http.ResponseWriter, r *http.Request) { util.WriteSuccessEmptyJSON(w) } + +// GetLicense returns product license +func GetLicense(w http.ResponseWriter, r *http.Request) { + // method := "GetLicense" + p := request.GetPersister(r) + + if !p.Context.Global { + writeForbiddenError(w) + return + } + + // SMTP settings + config := request.ConfigString("EDITION-LICENSE", "") + if len(config) == 0 { + config = "{}" + } + + x := &licenseXML{Key: "", Signature: ""} + lj := licenseJSON{} + + err := json.Unmarshal([]byte(config), &lj) + if err == nil { + x.Key = lj.Key + x.Signature = lj.Signature + } else { + fmt.Println(err) + } + + output, err := xml.MarshalIndent(x, " ", " ") + if err != nil { + fmt.Printf("error: %v\n", err) + } + + w.WriteHeader(http.StatusOK) + w.Write(output) + + // // marshal as JSON + // var y map[string]interface{} + // json.Unmarshal([]byte(config), &y) + + // json, err := json.Marshal(y) + // if err != nil { + // writeJSONMarshalError(w, method, "EDITION-LICENSE", err) + // return + // } + + // util.WriteSuccessBytes(w, json) +} + +// SaveLicense persists product license +func SaveLicense(w http.ResponseWriter, r *http.Request) { + method := "SaveLicense" + p := request.GetPersister(r) + + if !p.Context.Global { + writeForbiddenError(w) + return + } + + defer r.Body.Close() + + body, err := ioutil.ReadAll(r.Body) + if err != nil { + writePayloadError(w, method, err) + return + } + + var config string + config = string(body) + lj := licenseJSON{} + x := licenseXML{Key: "", Signature: ""} + + err = xml.Unmarshal([]byte(config), &x) + if err == nil { + lj.Key = x.Key + lj.Signature = x.Signature + } else { + fmt.Println(err) + } + + j, err := json.Marshal(lj) + js := "{}" + if err == nil { + js = string(j) + } + + request.ConfigSet("EDITION-LICENSE", js) + + util.WriteSuccessEmptyJSON(w) +} + +type licenseXML struct { + XMLName xml.Name `xml:"DocumizeLicense"` + Key string + Signature string +} +type licenseJSON struct { + Key string `json:"key"` + Signature string `json:"signature"` +} + +/* + + some key + some signature + +*/ diff --git a/core/api/endpoint/router.go b/core/api/endpoint/router.go index cb756b34..ed178d12 100644 --- a/core/api/endpoint/router.go +++ b/core/api/endpoint/router.go @@ -229,8 +229,10 @@ func init() { log.IfErr(Add(RoutePrefixPrivate, "documents/{documentID}/links", []string{"GET", "OPTIONS"}, nil, GetDocumentLinks)) // Global installation-wide config - log.IfErr(Add(RoutePrefixPrivate, "global", []string{"GET", "OPTIONS"}, nil, GetGlobalConfig)) - log.IfErr(Add(RoutePrefixPrivate, "global", []string{"PUT", "OPTIONS"}, nil, SaveGlobalConfig)) + log.IfErr(Add(RoutePrefixPrivate, "global/smtp", []string{"GET", "OPTIONS"}, nil, GetSMTPConfig)) + log.IfErr(Add(RoutePrefixPrivate, "global/smtp", []string{"PUT", "OPTIONS"}, nil, SaveSMTPConfig)) + log.IfErr(Add(RoutePrefixPrivate, "global/license", []string{"GET", "OPTIONS"}, nil, GetLicense)) + log.IfErr(Add(RoutePrefixPrivate, "global/license", []string{"PUT", "OPTIONS"}, nil, SaveLicense)) // Pinned items log.IfErr(Add(RoutePrefixPrivate, "pin/{userID}", []string{"POST", "OPTIONS"}, nil, AddPin)) diff --git a/core/api/endpoint/server.go b/core/api/endpoint/server.go index 7684cb1b..ec5ceedb 100644 --- a/core/api/endpoint/server.go +++ b/core/api/endpoint/server.go @@ -38,6 +38,9 @@ func init() { environment.GetString(&keyFile, "key", false, "the key.pem file used for https", nil) environment.GetString(&port, "port", false, "http/https port number", nil) environment.GetString(&forcePort2SSL, "forcesslport", false, "redirect given http port number to TLS", nil) + + // license state + log.Info(Product.License.Status()) } var testHost string // used during automated testing diff --git a/core/product.go b/core/product.go index 287e6247..cee134aa 100644 --- a/core/product.go +++ b/core/product.go @@ -12,6 +12,7 @@ package core import "fmt" +import "time" // ProdInfo describes a product type ProdInfo struct { @@ -21,6 +22,7 @@ type ProdInfo struct { Major string Minor string Patch string + License License } // Product returns product edition details @@ -31,6 +33,54 @@ func Product() (p ProdInfo) { p.Version = fmt.Sprintf("%s.%s.%s", p.Major, p.Minor, p.Patch) p.Edition = "Community" p.Title = fmt.Sprintf("%s Edition", p.Edition) + p.License = License{} - return p + return +} + +// License holds details of product license. +type License struct { + Name string `json:"name"` + Email string `json:"email"` + Edition string `json:"edition"` + Start time.Time `json:"start"` + End time.Time `json:"end"` + Seats int `json:"seats"` + Trial bool `json:"trial"` +} + +// IsEmpty determines if we have a license. +func (l *License) IsEmpty() bool { + return l.Seats == 0 && len(l.Name) == 0 && len(l.Email) == 0 && l.Start.Year() == 1 && l.End.Year() == 1 +} + +// IsValid determines if we have populated and valid license. +// An empty license is valid. +func (l *License) IsValid() bool { + if l.IsEmpty() { + return true + } + + now := time.Now().UTC() + return l.End.Day() <= now.Day() && l.End.Month() <= now.Month() && l.End.Year() <= now.Year() +} + +// Status returns formatted message stating if license is empty/populated and invalid/valid. +func (l *License) Status() string { + lp := "populated" + if l.IsEmpty() { + lp = "empty" + } + lv := "invalid" + if l.IsValid() { + lv = "valid" + } + + return fmt.Sprintf("License is %s and %s", lp, lv) +} + +// LicenseData holds encrypted data and is unpacked into License. +type LicenseData struct { + Key string `json:"key"` + Signature string `json:"signature"` }