summaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/i18n.go140
-rw-r--r--utils/license.go157
-rw-r--r--utils/license_test.go50
3 files changed, 347 insertions, 0 deletions
diff --git a/utils/i18n.go b/utils/i18n.go
new file mode 100644
index 000000000..4fc8c725a
--- /dev/null
+++ b/utils/i18n.go
@@ -0,0 +1,140 @@
+package utils
+
+import (
+ "io/ioutil"
+ "net/http"
+ "path/filepath"
+ "strings"
+
+ l4g "github.com/alecthomas/log4go"
+ "github.com/cloudfoundry/jibber_jabber"
+ "github.com/mattermost/platform/model"
+ "github.com/nicksnyder/go-i18n/i18n"
+)
+
+const (
+ SESSION_LOCALE = "MMLOCALE"
+)
+
+var T i18n.TranslateFunc
+var locales map[string]string = make(map[string]string)
+
+func InitTranslations() {
+ i18nDirectory := FindDir("i18n")
+ files, _ := ioutil.ReadDir(i18nDirectory)
+ for _, f := range files {
+ if filepath.Ext(f.Name()) == ".json" {
+ filename := f.Name()
+ locales[strings.Split(filename, ".")[0]] = i18nDirectory + filename
+ i18n.MustLoadTranslationFile(i18nDirectory + filename)
+ }
+ }
+
+ T = GetTranslationsBySystemLocale()
+}
+
+func GetTranslationsBySystemLocale() i18n.TranslateFunc {
+ locale := model.DEFAULT_LOCALE
+ if userLanguage, err := jibber_jabber.DetectLanguage(); err == nil {
+ locale = userLanguage
+ }
+
+ if locales[locale] == "" {
+ l4g.Error("Failed to load system translations for '%v' attempting to fall back to '%v'", locale, model.DEFAULT_LOCALE)
+
+ if locales[model.DEFAULT_LOCALE] == "" {
+ panic("Failed to load system translations for '" + model.DEFAULT_LOCALE + "'")
+ }
+ }
+
+ translations, _ := i18n.Tfunc(locale)
+ if translations == nil {
+ panic("Failed to load system translations")
+ }
+
+ l4g.Info(translations("utils.i18n.loaded"), locale, locales[locale])
+ return translations
+}
+
+func SetTranslations(locale string) i18n.TranslateFunc {
+ translations, _ := i18n.Tfunc(locale)
+ return translations
+}
+
+func GetTranslations(w http.ResponseWriter, r *http.Request) i18n.TranslateFunc {
+ translations, _ := getTranslationsAndLocale(w, r)
+ return translations
+}
+
+func GetTranslationsAndLocale(w http.ResponseWriter, r *http.Request) (i18n.TranslateFunc, string) {
+ return getTranslationsAndLocale(w, r)
+}
+
+func SetLocaleCookie(w http.ResponseWriter, lang string, sessionCacheInMinutes int) {
+ maxAge := (sessionCacheInMinutes * 60)
+ cookie := &http.Cookie{
+ Name: SESSION_LOCALE,
+ Value: lang,
+ Path: "/",
+ MaxAge: maxAge,
+ }
+
+ http.SetCookie(w, cookie)
+}
+
+// var keyRegexp = regexp.MustCompile(`:[[:word:]]+`)
+// func MaybeExpandNamedText(text string, args ...interface{}) string {
+// var (
+// arg = args[0]
+// argval = reflect.ValueOf(arg)
+// )
+// if argval.Kind() == reflect.Ptr {
+// argval = argval.Elem()
+// }
+
+// if argval.Kind() == reflect.Map && argval.Type().Key().Kind() == reflect.String {
+// return expandNamedText(text, func(key string) reflect.Value {
+// return argval.MapIndex(reflect.ValueOf(key))
+// })
+// }
+// if argval.Kind() != reflect.Struct {
+// return text
+// }
+
+// return expandNamedText(text, argval.FieldByName)
+// }
+
+// func expandNamedText(text string, keyGetter func(key string) reflect.Value) string {
+// return keyRegexp.ReplaceAllStringFunc(text, func(key string) string {
+// val := keyGetter(key[1:])
+// if !val.IsValid() {
+// return key
+// }
+// newVar, _ := val.Interface().(string)
+// return newVar
+// })
+// }
+
+func getTranslationsAndLocale(w http.ResponseWriter, r *http.Request) (i18n.TranslateFunc, string) {
+ var translations i18n.TranslateFunc
+ var _ error
+ localeCookie := ""
+ if cookie, err := r.Cookie(SESSION_LOCALE); err == nil {
+ localeCookie = cookie.Value
+ if locales[localeCookie] != "" {
+ translations, _ = i18n.Tfunc(localeCookie)
+ return translations, localeCookie
+ }
+ }
+
+ localeCookie = strings.Split(strings.Split(r.Header.Get("Accept-Language"), ",")[0], "-")[0]
+ if locales[localeCookie] != "" {
+ translations, _ = i18n.Tfunc(localeCookie)
+ SetLocaleCookie(w, localeCookie, 10)
+ return translations, localeCookie
+ }
+
+ translations, _ = i18n.Tfunc(model.DEFAULT_LOCALE)
+ SetLocaleCookie(w, model.DEFAULT_LOCALE, 10)
+ return translations, model.DEFAULT_LOCALE
+}
diff --git a/utils/license.go b/utils/license.go
new file mode 100644
index 000000000..7594e33af
--- /dev/null
+++ b/utils/license.go
@@ -0,0 +1,157 @@
+// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package utils
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/rsa"
+ "crypto/sha512"
+ "crypto/x509"
+ "encoding/base64"
+ "encoding/pem"
+ "io"
+ "os"
+ "path/filepath"
+ "strconv"
+ "strings"
+
+ l4g "github.com/alecthomas/log4go"
+
+ "github.com/mattermost/platform/model"
+)
+
+const (
+ LICENSE_FILENAME = "active.dat"
+)
+
+var IsLicensed bool = false
+var License *model.License = &model.License{}
+var ClientLicense map[string]string = make(map[string]string)
+
+// test public key
+var publicKey []byte = []byte(`-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3/k3Al9q1Xe+xngQ/yGn
+0suaJopea3Cpf6NjIHdO8sYTwLlxqt0Mdb+qBR9LbCjZfcNmqc5mZONvsyCEoN/5
+VoLdlv1m9ao2BSAWphUxE2CPdUWdLOsDbQWliSc5//UhiYeR+67Xxon0Hg0LKXF6
+PumRIWQenRHJWqlUQZ147e7/1v9ySVRZksKpvlmMDzgq+kCH/uyM1uVP3z7YXhlN
+K7vSSQYbt4cghvWQxDZFwpLlsChoY+mmzClgq+Yv6FLhj4/lk94twdOZau/AeZFJ
+NxpC+5KFhU+xSeeklNqwCgnlOyZ7qSTxmdJHb+60SwuYnnGIYzLJhY4LYDr4J+KR
+1wIDAQAB
+-----END PUBLIC KEY-----`)
+
+func LoadLicense() {
+ file, err := os.Open(LicenseLocation())
+ if err != nil {
+ l4g.Warn("Unable to open/find license file")
+ return
+ }
+ defer file.Close()
+
+ buf := bytes.NewBuffer(nil)
+ io.Copy(buf, file)
+
+ if success, licenseStr := ValidateLicense(buf.Bytes()); success {
+ license := model.LicenseFromJson(strings.NewReader(licenseStr))
+ SetLicense(license)
+ }
+
+ l4g.Warn("No valid enterprise license found")
+}
+
+func SetLicense(license *model.License) bool {
+ license.Features.SetDefaults()
+
+ if !license.IsExpired() && license.IsStarted() {
+ License = license
+ IsLicensed = true
+ ClientLicense = getClientLicense(license)
+ return true
+ }
+
+ return false
+}
+
+func LicenseLocation() string {
+ return filepath.Dir(CfgFileName) + "/" + LICENSE_FILENAME
+}
+
+func RemoveLicense() bool {
+ License = &model.License{}
+ IsLicensed = false
+ ClientLicense = getClientLicense(License)
+
+ if err := os.Remove(LicenseLocation()); err != nil {
+ l4g.Error("Unable to remove license file, err=%v", err.Error())
+ return false
+ }
+
+ return true
+}
+
+func ValidateLicense(signed []byte) (bool, string) {
+ decoded := make([]byte, base64.StdEncoding.DecodedLen(len(signed)))
+
+ _, err := base64.StdEncoding.Decode(decoded, signed)
+ if err != nil {
+ l4g.Error("Encountered error decoding license, err=%v", err.Error())
+ return false, ""
+ }
+
+ if len(decoded) <= 256 {
+ l4g.Error("Signed license not long enough")
+ return false, ""
+ }
+
+ // remove null terminator
+ if decoded[len(decoded)-1] == byte(0) {
+ decoded = decoded[:len(decoded)-1]
+ }
+
+ plaintext := decoded[:len(decoded)-256]
+ signature := decoded[len(decoded)-256:]
+
+ block, _ := pem.Decode(publicKey)
+
+ public, err := x509.ParsePKIXPublicKey(block.Bytes)
+ if err != nil {
+ l4g.Error("Encountered error signing license, err=%v", err.Error())
+ return false, ""
+ }
+
+ rsaPublic := public.(*rsa.PublicKey)
+
+ h := sha512.New()
+ h.Write(plaintext)
+ d := h.Sum(nil)
+
+ err = rsa.VerifyPKCS1v15(rsaPublic, crypto.SHA512, d, signature)
+ if err != nil {
+ l4g.Error("Invalid signature, err=%v", err.Error())
+ return false, ""
+ }
+
+ return true, string(plaintext)
+}
+
+func getClientLicense(l *model.License) map[string]string {
+ props := make(map[string]string)
+
+ props["IsLicensed"] = strconv.FormatBool(IsLicensed)
+
+ if IsLicensed {
+ props["Users"] = strconv.Itoa(*l.Features.Users)
+ props["LDAP"] = strconv.FormatBool(*l.Features.LDAP)
+ props["GoogleSSO"] = strconv.FormatBool(*l.Features.GoogleSSO)
+ props["IssuedAt"] = strconv.FormatInt(l.IssuedAt, 10)
+ props["StartsAt"] = strconv.FormatInt(l.StartsAt, 10)
+ props["ExpiresAt"] = strconv.FormatInt(l.ExpiresAt, 10)
+ props["Name"] = l.Customer.Name
+ props["Email"] = l.Customer.Email
+ props["Company"] = l.Customer.Company
+ props["PhoneNumber"] = l.Customer.PhoneNumber
+ }
+
+ return props
+}
diff --git a/utils/license_test.go b/utils/license_test.go
new file mode 100644
index 000000000..826107032
--- /dev/null
+++ b/utils/license_test.go
@@ -0,0 +1,50 @@
+// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+package utils
+
+import (
+ "github.com/mattermost/platform/model"
+ "testing"
+)
+
+func TestSetLicense(t *testing.T) {
+ l1 := &model.License{}
+ l1.Features = &model.Features{}
+ l1.Customer = &model.Customer{}
+ l1.StartsAt = model.GetMillis() - 1000
+ l1.ExpiresAt = model.GetMillis() + 100000
+ if ok := SetLicense(l1); !ok {
+ t.Fatal("license should have worked")
+ }
+
+ l2 := &model.License{}
+ l2.Features = &model.Features{}
+ l2.Customer = &model.Customer{}
+ l2.StartsAt = model.GetMillis() - 1000
+ l2.ExpiresAt = model.GetMillis() - 100
+ if ok := SetLicense(l2); ok {
+ t.Fatal("license should have failed")
+ }
+
+ l3 := &model.License{}
+ l3.Features = &model.Features{}
+ l3.Customer = &model.Customer{}
+ l3.StartsAt = model.GetMillis() + 10000
+ l3.ExpiresAt = model.GetMillis() + 100000
+ if ok := SetLicense(l3); ok {
+ t.Fatal("license should have failed")
+ }
+}
+
+func TestValidateLicense(t *testing.T) {
+ b1 := []byte("junk")
+ if ok, _ := ValidateLicense(b1); ok {
+ t.Fatal("should have failed - bad license")
+ }
+
+ b2 := []byte("junkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunkjunk")
+ if ok, _ := ValidateLicense(b2); ok {
+ t.Fatal("should have failed - bad license")
+ }
+}