summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/mattermost/mattermost-server/v6/model/utils.go
diff options
context:
space:
mode:
authorWim <wim@42.be>2021-10-16 23:11:32 +0200
committerWim <wim@42.be>2021-10-16 23:23:24 +0200
commit20f6c05ec50739d31f4dbe9fde0d223f2c43f6e8 (patch)
tree230edca06449a8d1755f08aabf45a03e07e6f17c /vendor/github.com/mattermost/mattermost-server/v6/model/utils.go
parent57fce93af7f64f025cec6f3ed6088163086bc9fe (diff)
downloadmatterbridge-msglm-20f6c05ec50739d31f4dbe9fde0d223f2c43f6e8.tar.gz
matterbridge-msglm-20f6c05ec50739d31f4dbe9fde0d223f2c43f6e8.tar.bz2
matterbridge-msglm-20f6c05ec50739d31f4dbe9fde0d223f2c43f6e8.zip
Update vendor
Diffstat (limited to 'vendor/github.com/mattermost/mattermost-server/v6/model/utils.go')
-rw-r--r--vendor/github.com/mattermost/mattermost-server/v6/model/utils.go587
1 files changed, 587 insertions, 0 deletions
diff --git a/vendor/github.com/mattermost/mattermost-server/v6/model/utils.go b/vendor/github.com/mattermost/mattermost-server/v6/model/utils.go
new file mode 100644
index 00000000..fab3f494
--- /dev/null
+++ b/vendor/github.com/mattermost/mattermost-server/v6/model/utils.go
@@ -0,0 +1,587 @@
+// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
+// See LICENSE.txt for license information.
+
+package model
+
+import (
+ "bytes"
+ "crypto/rand"
+ "encoding/base32"
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net"
+ "net/http"
+ "net/mail"
+ "net/url"
+ "regexp"
+ "sort"
+ "strings"
+ "sync"
+ "time"
+ "unicode"
+
+ "github.com/mattermost/mattermost-server/v6/shared/i18n"
+ "github.com/pborman/uuid"
+)
+
+const (
+ LowercaseLetters = "abcdefghijklmnopqrstuvwxyz"
+ UppercaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ NUMBERS = "0123456789"
+ SYMBOLS = " !\"\\#$%&'()*+,-./:;<=>?@[]^_`|~"
+)
+
+type StringInterface map[string]interface{}
+type StringArray []string
+
+func (sa StringArray) Remove(input string) StringArray {
+ for index := range sa {
+ if sa[index] == input {
+ ret := make(StringArray, 0, len(sa)-1)
+ ret = append(ret, sa[:index]...)
+ return append(ret, sa[index+1:]...)
+ }
+ }
+ return sa
+}
+
+func (sa StringArray) Contains(input string) bool {
+ for index := range sa {
+ if sa[index] == input {
+ return true
+ }
+ }
+
+ return false
+}
+func (sa StringArray) Equals(input StringArray) bool {
+
+ if len(sa) != len(input) {
+ return false
+ }
+
+ for index := range sa {
+
+ if sa[index] != input[index] {
+ return false
+ }
+ }
+
+ return true
+}
+
+var translateFunc i18n.TranslateFunc
+var translateFuncOnce sync.Once
+
+func AppErrorInit(t i18n.TranslateFunc) {
+ translateFuncOnce.Do(func() {
+ translateFunc = t
+ })
+}
+
+type AppError struct {
+ Id string `json:"id"`
+ Message string `json:"message"` // Message to be display to the end user without debugging information
+ DetailedError string `json:"detailed_error"` // Internal error string to help the developer
+ RequestId string `json:"request_id,omitempty"` // The RequestId that's also set in the header
+ StatusCode int `json:"status_code,omitempty"` // The http status code
+ Where string `json:"-"` // The function where it happened in the form of Struct.Func
+ IsOAuth bool `json:"is_oauth,omitempty"` // Whether the error is OAuth specific
+ params map[string]interface{}
+}
+
+func (er *AppError) Error() string {
+ return er.Where + ": " + er.Message + ", " + er.DetailedError
+}
+
+func (er *AppError) Translate(T i18n.TranslateFunc) {
+ if T == nil {
+ er.Message = er.Id
+ return
+ }
+
+ if er.params == nil {
+ er.Message = T(er.Id)
+ } else {
+ er.Message = T(er.Id, er.params)
+ }
+}
+
+func (er *AppError) SystemMessage(T i18n.TranslateFunc) string {
+ if er.params == nil {
+ return T(er.Id)
+ }
+ return T(er.Id, er.params)
+}
+
+func (er *AppError) ToJSON() string {
+ b, _ := json.Marshal(er)
+ return string(b)
+}
+
+// AppErrorFromJSON will decode the input and return an AppError
+func AppErrorFromJSON(data io.Reader) *AppError {
+ str := ""
+ bytes, rerr := ioutil.ReadAll(data)
+ if rerr != nil {
+ str = rerr.Error()
+ } else {
+ str = string(bytes)
+ }
+
+ decoder := json.NewDecoder(strings.NewReader(str))
+ var er AppError
+ err := decoder.Decode(&er)
+ if err != nil {
+ return NewAppError("AppErrorFromJSON", "model.utils.decode_json.app_error", nil, "body: "+str, http.StatusInternalServerError)
+ }
+ return &er
+}
+
+func NewAppError(where string, id string, params map[string]interface{}, details string, status int) *AppError {
+ ap := &AppError{}
+ ap.Id = id
+ ap.params = params
+ ap.Message = id
+ ap.Where = where
+ ap.DetailedError = details
+ ap.StatusCode = status
+ ap.IsOAuth = false
+ ap.Translate(translateFunc)
+ return ap
+}
+
+var encoding = base32.NewEncoding("ybndrfg8ejkmcpqxot1uwisza345h769")
+
+// NewId is a globally unique identifier. It is a [A-Z0-9] string 26
+// characters long. It is a UUID version 4 Guid that is zbased32 encoded
+// with the padding stripped off.
+func NewId() string {
+ var b bytes.Buffer
+ encoder := base32.NewEncoder(encoding, &b)
+ encoder.Write(uuid.NewRandom())
+ encoder.Close()
+ b.Truncate(26) // removes the '==' padding
+ return b.String()
+}
+
+// NewRandomTeamName is a NewId that will be a valid team name.
+func NewRandomTeamName() string {
+ teamName := NewId()
+ for IsReservedTeamName(teamName) {
+ teamName = NewId()
+ }
+ return teamName
+}
+
+// NewRandomString returns a random string of the given length.
+// The resulting entropy will be (5 * length) bits.
+func NewRandomString(length int) string {
+ data := make([]byte, 1+(length*5/8))
+ rand.Read(data)
+ return encoding.EncodeToString(data)[:length]
+}
+
+// GetMillis is a convenience method to get milliseconds since epoch.
+func GetMillis() int64 {
+ return time.Now().UnixNano() / int64(time.Millisecond)
+}
+
+// GetMillisForTime is a convenience method to get milliseconds since epoch for provided Time.
+func GetMillisForTime(thisTime time.Time) int64 {
+ return thisTime.UnixNano() / int64(time.Millisecond)
+}
+
+// GetTimeForMillis is a convenience method to get time.Time for milliseconds since epoch.
+func GetTimeForMillis(millis int64) time.Time {
+ return time.Unix(0, millis*int64(time.Millisecond))
+}
+
+// PadDateStringZeros is a convenience method to pad 2 digit date parts with zeros to meet ISO 8601 format
+func PadDateStringZeros(dateString string) string {
+ parts := strings.Split(dateString, "-")
+ for index, part := range parts {
+ if len(part) == 1 {
+ parts[index] = "0" + part
+ }
+ }
+ dateString = strings.Join(parts[:], "-")
+ return dateString
+}
+
+// GetStartOfDayMillis is a convenience method to get milliseconds since epoch for provided date's start of day
+func GetStartOfDayMillis(thisTime time.Time, timeZoneOffset int) int64 {
+ localSearchTimeZone := time.FixedZone("Local Search Time Zone", timeZoneOffset)
+ resultTime := time.Date(thisTime.Year(), thisTime.Month(), thisTime.Day(), 0, 0, 0, 0, localSearchTimeZone)
+ return GetMillisForTime(resultTime)
+}
+
+// GetEndOfDayMillis is a convenience method to get milliseconds since epoch for provided date's end of day
+func GetEndOfDayMillis(thisTime time.Time, timeZoneOffset int) int64 {
+ localSearchTimeZone := time.FixedZone("Local Search Time Zone", timeZoneOffset)
+ resultTime := time.Date(thisTime.Year(), thisTime.Month(), thisTime.Day(), 23, 59, 59, 999999999, localSearchTimeZone)
+ return GetMillisForTime(resultTime)
+}
+
+func CopyStringMap(originalMap map[string]string) map[string]string {
+ copyMap := make(map[string]string, len(originalMap))
+ for k, v := range originalMap {
+ copyMap[k] = v
+ }
+ return copyMap
+}
+
+// MapToJSON converts a map to a json string
+func MapToJSON(objmap map[string]string) string {
+ b, _ := json.Marshal(objmap)
+ return string(b)
+}
+
+// MapBoolToJSON converts a map to a json string
+func MapBoolToJSON(objmap map[string]bool) string {
+ b, _ := json.Marshal(objmap)
+ return string(b)
+}
+
+// MapFromJSON will decode the key/value pair map
+func MapFromJSON(data io.Reader) map[string]string {
+ decoder := json.NewDecoder(data)
+
+ var objmap map[string]string
+ if err := decoder.Decode(&objmap); err != nil {
+ return make(map[string]string)
+ }
+ return objmap
+}
+
+// MapFromJSON will decode the key/value pair map
+func MapBoolFromJSON(data io.Reader) map[string]bool {
+ decoder := json.NewDecoder(data)
+
+ var objmap map[string]bool
+ if err := decoder.Decode(&objmap); err != nil {
+ return make(map[string]bool)
+ }
+ return objmap
+}
+
+func ArrayToJSON(objmap []string) string {
+ b, _ := json.Marshal(objmap)
+ return string(b)
+}
+
+func ArrayFromJSON(data io.Reader) []string {
+ decoder := json.NewDecoder(data)
+
+ var objmap []string
+ if err := decoder.Decode(&objmap); err != nil {
+ return make([]string, 0)
+ }
+ return objmap
+}
+
+func ArrayFromInterface(data interface{}) []string {
+ stringArray := []string{}
+
+ dataArray, ok := data.([]interface{})
+ if !ok {
+ return stringArray
+ }
+
+ for _, v := range dataArray {
+ if str, ok := v.(string); ok {
+ stringArray = append(stringArray, str)
+ }
+ }
+
+ return stringArray
+}
+
+func StringInterfaceToJSON(objmap map[string]interface{}) string {
+ b, _ := json.Marshal(objmap)
+ return string(b)
+}
+
+func StringInterfaceFromJSON(data io.Reader) map[string]interface{} {
+ decoder := json.NewDecoder(data)
+
+ var objmap map[string]interface{}
+ if err := decoder.Decode(&objmap); err != nil {
+ return make(map[string]interface{})
+ }
+ return objmap
+}
+
+// ToJSON serializes an arbitrary data type to JSON, discarding the error.
+func ToJSON(v interface{}) []byte {
+ b, _ := json.Marshal(v)
+ return b
+}
+
+func GetServerIPAddress(iface string) string {
+ var addrs []net.Addr
+ if iface == "" {
+ var err error
+ addrs, err = net.InterfaceAddrs()
+ if err != nil {
+ return ""
+ }
+ } else {
+ interfaces, err := net.Interfaces()
+ if err != nil {
+ return ""
+ }
+ for _, i := range interfaces {
+ if i.Name == iface {
+ addrs, err = i.Addrs()
+ if err != nil {
+ return ""
+ }
+ break
+ }
+ }
+ }
+
+ for _, addr := range addrs {
+
+ if ip, ok := addr.(*net.IPNet); ok && !ip.IP.IsLoopback() && !ip.IP.IsLinkLocalUnicast() && !ip.IP.IsLinkLocalMulticast() {
+ if ip.IP.To4() != nil {
+ return ip.IP.String()
+ }
+ }
+ }
+
+ return ""
+}
+
+func isLower(s string) bool {
+ return strings.ToLower(s) == s
+}
+
+func IsValidEmail(email string) bool {
+ if !isLower(email) {
+ return false
+ }
+
+ if addr, err := mail.ParseAddress(email); err != nil {
+ return false
+ } else if addr.Name != "" {
+ // mail.ParseAddress accepts input of the form "Billy Bob <billy@example.com>" which we don't allow
+ return false
+ }
+
+ return true
+}
+
+var reservedName = []string{
+ "admin",
+ "api",
+ "channel",
+ "claim",
+ "error",
+ "files",
+ "help",
+ "landing",
+ "login",
+ "mfa",
+ "oauth",
+ "plug",
+ "plugins",
+ "post",
+ "signup",
+ "boards",
+ "playbooks",
+}
+
+func IsValidChannelIdentifier(s string) bool {
+
+ if !IsValidAlphaNumHyphenUnderscore(s, true) {
+ return false
+ }
+
+ if len(s) < ChannelNameMinLength {
+ return false
+ }
+
+ return true
+}
+
+var (
+ validAlphaNum = regexp.MustCompile(`^[a-z0-9]+([a-z\-0-9]+|(__)?)[a-z0-9]+$`)
+ validAlphaNumHyphenUnderscore = regexp.MustCompile(`^[a-z0-9]+([a-z\-\_0-9]+|(__)?)[a-z0-9]+$`)
+ validSimpleAlphaNumHyphenUnderscore = regexp.MustCompile(`^[a-zA-Z0-9\-_]+$`)
+ validSimpleAlphaNumHyphenUnderscorePlus = regexp.MustCompile(`^[a-zA-Z0-9+_-]+$`)
+)
+
+func isValidAlphaNum(s string) bool {
+ return validAlphaNum.MatchString(s)
+}
+
+func IsValidAlphaNumHyphenUnderscore(s string, withFormat bool) bool {
+ if withFormat {
+ return validAlphaNumHyphenUnderscore.MatchString(s)
+ }
+ return validSimpleAlphaNumHyphenUnderscore.MatchString(s)
+}
+
+func IsValidAlphaNumHyphenUnderscorePlus(s string) bool {
+ return validSimpleAlphaNumHyphenUnderscorePlus.MatchString(s)
+}
+
+func Etag(parts ...interface{}) string {
+
+ etag := CurrentVersion
+
+ for _, part := range parts {
+ etag += fmt.Sprintf(".%v", part)
+ }
+
+ return etag
+}
+
+var (
+ validHashtag = regexp.MustCompile(`^(#\pL[\pL\d\-_.]*[\pL\d])$`)
+ puncStart = regexp.MustCompile(`^[^\pL\d\s#]+`)
+ hashtagStart = regexp.MustCompile(`^#{2,}`)
+ puncEnd = regexp.MustCompile(`[^\pL\d\s]+$`)
+)
+
+func ParseHashtags(text string) (string, string) {
+ words := strings.Fields(text)
+
+ hashtagString := ""
+ plainString := ""
+ for _, word := range words {
+ // trim off surrounding punctuation
+ word = puncStart.ReplaceAllString(word, "")
+ word = puncEnd.ReplaceAllString(word, "")
+
+ // and remove extra pound #s
+ word = hashtagStart.ReplaceAllString(word, "#")
+
+ if validHashtag.MatchString(word) {
+ hashtagString += " " + word
+ } else {
+ plainString += " " + word
+ }
+ }
+
+ if len(hashtagString) > 1000 {
+ hashtagString = hashtagString[:999]
+ lastSpace := strings.LastIndex(hashtagString, " ")
+ if lastSpace > -1 {
+ hashtagString = hashtagString[:lastSpace]
+ } else {
+ hashtagString = ""
+ }
+ }
+
+ return strings.TrimSpace(hashtagString), strings.TrimSpace(plainString)
+}
+
+func ClearMentionTags(post string) string {
+ post = strings.Replace(post, "<mention>", "", -1)
+ post = strings.Replace(post, "</mention>", "", -1)
+ return post
+}
+
+func IsValidHTTPURL(rawURL string) bool {
+ if strings.Index(rawURL, "http://") != 0 && strings.Index(rawURL, "https://") != 0 {
+ return false
+ }
+
+ if u, err := url.ParseRequestURI(rawURL); err != nil || u.Scheme == "" || u.Host == "" {
+ return false
+ }
+
+ return true
+}
+
+func IsValidId(value string) bool {
+ if len(value) != 26 {
+ return false
+ }
+
+ for _, r := range value {
+ if !unicode.IsLetter(r) && !unicode.IsNumber(r) {
+ return false
+ }
+ }
+
+ return true
+}
+
+// RemoveDuplicateStrings does an in-place removal of duplicate strings
+// from the input slice. The original slice gets modified.
+func RemoveDuplicateStrings(in []string) []string {
+ // In-place de-dup.
+ // Copied from https://github.com/golang/go/wiki/SliceTricks#in-place-deduplicate-comparable
+ if len(in) == 0 {
+ return in
+ }
+ sort.Strings(in)
+ j := 0
+ for i := 1; i < len(in); i++ {
+ if in[j] == in[i] {
+ continue
+ }
+ j++
+ in[j] = in[i]
+ }
+ return in[:j+1]
+}
+
+func GetPreferredTimezone(timezone StringMap) string {
+ if timezone["useAutomaticTimezone"] == "true" {
+ return timezone["automaticTimezone"]
+ }
+
+ return timezone["manualTimezone"]
+}
+
+// SanitizeUnicode will remove undesirable Unicode characters from a string.
+func SanitizeUnicode(s string) string {
+ return strings.Map(filterBlocklist, s)
+}
+
+// filterBlocklist returns `r` if it is not in the blocklist, otherwise drop (-1).
+// Blocklist is taken from https://www.w3.org/TR/unicode-xml/#Charlist
+func filterBlocklist(r rune) rune {
+ const drop = -1
+ switch r {
+ case '\u0340', '\u0341': // clones of grave and acute; deprecated in Unicode
+ return drop
+ case '\u17A3', '\u17D3': // obsolete characters for Khmer; deprecated in Unicode
+ return drop
+ case '\u2028', '\u2029': // line and paragraph separator
+ return drop
+ case '\u202A', '\u202B', '\u202C', '\u202D', '\u202E': // BIDI embedding controls
+ return drop
+ case '\u206A', '\u206B': // activate/inhibit symmetric swapping; deprecated in Unicode
+ return drop
+ case '\u206C', '\u206D': // activate/inhibit Arabic form shaping; deprecated in Unicode
+ return drop
+ case '\u206E', '\u206F': // activate/inhibit national digit shapes; deprecated in Unicode
+ return drop
+ case '\uFFF9', '\uFFFA', '\uFFFB': // interlinear annotation characters
+ return drop
+ case '\uFEFF': // byte order mark
+ return drop
+ case '\uFFFC': // object replacement character
+ return drop
+ }
+
+ // Scoping for musical notation
+ if r >= 0x0001D173 && r <= 0x0001D17A {
+ return drop
+ }
+
+ // Language tag code points
+ if r >= 0x000E0000 && r <= 0x000E007F {
+ return drop
+ }
+
+ return r
+}