From f219243eb77546afbaaa7bc25d347952e1e2bbae Mon Sep 17 00:00:00 2001 From: "kali kaneko (leap communications)" Date: Mon, 15 Nov 2021 21:35:53 +0100 Subject: [feat] naive motd json format implementation --- branding/motd-cli/.gitignore | 1 + branding/motd-cli/README.md | 57 +++++++++++++++++ branding/motd-cli/main.go | 120 ++++++++++++++++++++++++++++++++++++ branding/motd-cli/motd-example.json | 14 +++++ 4 files changed, 192 insertions(+) create mode 100644 branding/motd-cli/.gitignore create mode 100644 branding/motd-cli/README.md create mode 100644 branding/motd-cli/main.go create mode 100644 branding/motd-cli/motd-example.json diff --git a/branding/motd-cli/.gitignore b/branding/motd-cli/.gitignore new file mode 100644 index 0000000..e26717e --- /dev/null +++ b/branding/motd-cli/.gitignore @@ -0,0 +1 @@ +motd-cli diff --git a/branding/motd-cli/README.md b/branding/motd-cli/README.md new file mode 100644 index 0000000..cfe8a38 --- /dev/null +++ b/branding/motd-cli/README.md @@ -0,0 +1,57 @@ +MOTD (message of the day) +========================= + +This is a stub until a more sophisticated motd mechanism can be implemented in +the future, with better platform integration. + +Providers can opt-in to the motd feature (only riseup is using it at the moment). + +If motd is enabled for a given provider, the client will attempt to fetch +the motd.json file from a well-known URL, and will display the first valid +message on the splash screen. + +The structure of the `motd.json` file is like follows: + +``` +{ + "motd": [{ + "begin": "Jan 1 2021 00:00:00", + "end": "Dec 31 2021 23:59:00", + "type": "daily", + "platform": "all", + "text": [ + { "lang": "en", + "str": "This is a test!"}, + { "lang": "es", + "str": "Esto es una pruebita!"} + ]} + ] +} +``` + +Valid values are: + +* Begin, End are date strings, like "Jan 1 2021 00:00:00". +* Type: "once" for a one-shot message, "daily" for a message that is displayed daily during the specified duration. +* Platform: one of "windows", "linux", "osx" or "all". + +The text message can contain links. + +You can use the `motd-cli` tool to parse and validate the json: + +``` +❯ ./motd-cli +file: motd-example.json +count: 1 + +Message 1 ✓ +----------- +Type: daily ✓ +Platform: all ✓ +Languages: 2 ✓ +``` + +Notes: I'm considering adding an explicit layer of verification of the motd +payload. Please comment on +[#554](https://0xacab.org/leap/bitmask-vpn/-/issues/554) if you have an opinion +on this. diff --git a/branding/motd-cli/main.go b/branding/motd-cli/main.go new file mode 100644 index 0000000..6cfd29e --- /dev/null +++ b/branding/motd-cli/main.go @@ -0,0 +1,120 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "io/ioutil" + "os" +) + +const defaultFile = "motd-example.json" + +const OK = "✓" +const WRONG = "☓" + +/* TODO move structs to pkg/config/motd module, import from there */ + +type Messages struct { + Messages []Message `json:"motd"` +} + +func (m *Messages) Length() int { + return len(m.Messages) +} + +type Message struct { + Begin string `json:"begin"` + End string `json:"end"` + Type string `json:"type"` + Platform string `json:"platform"` + Text []LocalizedText `json:"text"` +} + +func (m *Message) IsValid() bool { + valid := (m.IsValidBegin() && m.IsValidEnd() && + m.IsValidType() && m.IsValidPlatform() && m.HasLocalizedText()) + return valid +} + +func (m *Message) IsValidBegin() bool { + return true +} + +func (m *Message) IsValidEnd() bool { + return true +} + +func (m *Message) IsValidType() bool { + switch m.Type { + case "once", "daily": + return true + default: + return false + } +} + +func (m *Message) IsValidPlatform() bool { + switch m.Platform { + case "windows", "linux", "osx", "all": + return true + default: + return false + } +} + +func (m *Message) HasLocalizedText() bool { + return true +} + +type LocalizedText struct { + Lang string `json:"lang"` + Str string `json:"str"` +} + +func main() { + // TODO pass url flag too, to fetch and validate remote file + file := flag.String("file", "", "file to validate") + flag.Parse() + f := *file + if f == "" { + f = defaultFile + } + + fmt.Println("file:", f) + m := parseFile(f) + fmt.Printf("count: %v\n", m.Length()) + fmt.Println() + for i, msg := range m.Messages { + fmt.Printf("Message %d %v\n-----------\n", i+1, mark(msg.IsValid())) + fmt.Printf("Type: %s %v\n", msg.Type, mark(msg.IsValidType())) + fmt.Printf("Platform: %s %v\n", msg.Platform, mark(msg.IsValidPlatform())) + fmt.Printf("Languages: %d %v\n", len(msg.Text), mark(msg.HasLocalizedText())) + if !msg.IsValid() { + os.Exit(1) + } + } +} + +func parseFile(f string) Messages { + jsonFile, err := os.Open(f) + if err != nil { + panic(err) + } + defer jsonFile.Close() + byteVal, err := ioutil.ReadAll(jsonFile) + if err != nil { + panic(err) + } + var m Messages + json.Unmarshal(byteVal, &m) + return m +} + +func mark(val bool) string { + if val { + return OK + } else { + return WRONG + } +} diff --git a/branding/motd-cli/motd-example.json b/branding/motd-cli/motd-example.json new file mode 100644 index 0000000..47bf635 --- /dev/null +++ b/branding/motd-cli/motd-example.json @@ -0,0 +1,14 @@ +{ + "motd": [{ + "begin": "Jan 1 2021 00:00:00", + "end": "Dec 31 2021 23:59:00", + "type": "daily", + "platform": "all", + "text": [ + { "lang": "en", + "str": "This is a test!"}, + { "lang": "es", + "str": "Esto es una pruebita!"} + ]} + ] +} -- cgit v1.2.3