{"id":42068470,"url":"https://github.com/kingcobra2468/cot","last_synced_at":"2026-01-26T08:31:31.255Z","repository":{"id":38461199,"uuid":"461112064","full_name":"kingcobra2468/cot","owner":"kingcobra2468","description":"Transmit user-defined commands via SMS/MMS, bypassing port forwarding hassle.","archived":false,"fork":false,"pushed_at":"2024-02-11T22:37:07.000Z","size":311,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-06-21T03:18:48.128Z","etag":null,"topics":["command","commands","go","mms","pgp","sms","text"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kingcobra2468.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-02-19T06:54:28.000Z","updated_at":"2023-08-12T23:51:03.000Z","dependencies_parsed_at":"2022-08-19T06:21:18.909Z","dependency_job_id":"293466f6-7c83-4339-9c5c-44bcc805d7e4","html_url":"https://github.com/kingcobra2468/cot","commit_stats":{"total_commits":50,"total_committers":2,"mean_commits":25.0,"dds":"0.020000000000000018","last_synced_commit":"93ab1c3c6866c47865f8d08d691ed7f35c26932e"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/kingcobra2468/cot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kingcobra2468%2Fcot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kingcobra2468%2Fcot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kingcobra2468%2Fcot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kingcobra2468%2Fcot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kingcobra2468","download_url":"https://codeload.github.com/kingcobra2468/cot/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kingcobra2468%2Fcot/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28770798,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-26T07:45:00.504Z","status":"ssl_error","status_checked_at":"2026-01-26T07:45:00.070Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["command","commands","go","mms","pgp","sms","text"],"created_at":"2026-01-26T08:31:30.585Z","updated_at":"2026-01-26T08:31:31.247Z","avatar_url":"https://github.com/kingcobra2468.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# **COT**\n\nCommands over text(COT) is platform for bridging internal services and mobile users\nover the SMS/MMS protocol. Through a rich and programmable interface, one is able to define\nand fine-tune commands designated to internal services without doing any port-forwarding.\n\nCOT's main benefit arises with the ability to interact with internal services without\nthe need to do any port forwarding or exposure to the public internet. Thus, with COT\nrunning on the same network as the internal services, commands can be created along with\nclient service wrappers which will accept requests from cot and then further pass them\non to the internal services.\n\n## **Terminology**\n\n- **Client Number=** phone number that sends the command request.\n- **GVoice Number=** Gvoice phone number that services as receiver for commands that\n  come from client numbers.\n- **GVMS=** microservice for interacting with GVoice's APIs.\n- **Client Service=** user-defined service that is implemented externally of COT and is\n  responsible for taking in a command request, executing it, and returning the response.\n\n## **Architecture**\n\n![photo](images/cot.jpg)\n\nCOT, being generic, enables one to create any command they want as long as one defines\nit within `cot_sm.yaml`. Within the config file, one would specify:\n\n1. The name of the service and a list of commands that hit various endpoints of such service.\n2. List of client numbers authorized to use the command.\n\n## **Flow**\n\nThe end-to-end flow of COT is as follows:\n\n1. COT initializes a worker that checks the (GVoice Number, Client Number)\n   link periodically by polling GVMS. *By listening to only the subnet of defined client numbers,\n   COT, by nature, will ignore all numbers that have not been whitelisted by any of the\n   services within `cot_sm.yaml`.*\n2. A client sends a command in the format \"[cmd] [arg 0] [arg 1] ... [arg N]\" (split into tokens by\n   the space delimiter) to a GVoice number that COT polls.\n3. On detection of a new user command, COT parsers the command and checks if the client number is\n   authorized to run this command. Non-authorized commands will be rejected. Likewise, COT also checks\n   if the command exists.\n4. COT tries to match the user command to a given command of a service by doing pattern checking against\n   the input. In the case were no patterns match, an error is returned. Otherwise, the arguments are\n   reformated into appropriate arg groups and the command is sent to the configured service + endpoint along\n   with the defined HTTP method.\n5. The output of the command would then parsed based on the response configuration and is then sent back\n   to the client number.\n\n## **Encryption**\n\n![photo](images/cot_encryption.jpg)\n\nGiven that the SMS/MMS protocol is the foundation for COT, all messages will be visible\nby default. This includes but is not limited to ATT, Verizon, Google (due to GVoice), among\nother parties. Thus, this pushes the need for encryption.\n\nAs seen in the diagram, COT features 3 main flows, though further tweaking is possible with some\nlimitations.\n\n### **Flows**\n\n#### **No Encryption Flow**\n\nThis is the least secure of all flows and should be used in the case where the 2 other flows are\nnot viable.\n\n#### **PGP Encryption Flow**\n\nThis flow requires the client number to sign the command request with COT's public key prior to\nsending the message. The ASCII armored message will then be sent to COT. COT will send the response\nencrypted with the client number's public key.\n\n#### **PGP Encryption Flow \u0026 Base64**\n\nThis flow requires the client number to sign the command request with COT's public key prior to\nsending the message. Afterwards, the ASCII armored message would then need to be base64 encoded.\nIn the response message, COT will do the same and base64 encode the ASCII armoured message. The\nreason behind base64 encoding is due to some MMS/SMS clients on Android doing compression. Even\nthough the compression might seem harmless, PGP requires certain schema and this will render the\nmessage useless. Thus, using base64 will preserve all the formatting in order to prevent corruption.\n\n### **Note on PGP Signatures**\n\nFor the *PGP Encryption* and *PGP Encryption \u0026 Base64* flows, the option to set\n`COT_SIG_VERIFICATION` is possible. This will validate that the input command is signed by\nthe client number and will also sign the response with COT's private key. However, some SMS/MMS\nphone clients contain message size caps (even though MMS theoretically supports 5Mb messages), and\nthus this option should might not work everywhere. Thus, unless tested that it works for your needs,\n`COT_SIG_VERIFICATION` should remain as `false`. If set to false, avoid ensure that signing is off\nfrom the PGP client app used on the client number phone, in order to avoid large message sizes.\n\n### **Note on PGP and Base64 Encoding From Client Side**\n\nSince there is no user client for COT as it is intended to use the default SMS/MMS client, one\nwould have to download a PGP encoding/decoding as well as a base64 encoding/decoding app from the\nApp Store/Play Store and do the steps themselves each time.\n\n#### **PGP Encryption Flow**\n\n1. Encrypt command with PGP app.\n2. Send output to COT via SMS/MMS client.\n3. After response arrives from COT, paste it into PGP app's decoder and see command output.\n\n#### **PGP Encryption \u0026 Base64 Flow**\n\n1. Encrypt command with PGP app.\n2. Paste encrypted message into encoder of Base64 app.\n3. Send output to COT via SMS/MMS client.\n4. After response arrives from COT, paste it into decoder of Base64 app.\n5. Copy output and paste into PGP app's decoder and see command output.\n\n## **Configuration**\n\n### **General Configuration**\n\nMost configuration is done via the `cot_sm.yaml` file which needs to be copied/renamed from\n`cot_sm_template.yaml`. By default, the file needs to be located in the same directory as\nthe executable or `main.go`, unless an alternate path is specified via the `COT_CONF_DIR`\nenvironment variable.\n\n#### **Sample Configuration**\n\nThe best way to explain the configuration achievable with COT is through an example `cot_sm.yaml`\nfile. Note that none of the data is real and the numbers are fake and should not be contacted.\n\n```yaml\n---\ngvms:\n  hostname: \"192.168.1.10\"\n  port: 7777\ngvoice_number: 11111111111\nservices:\n  - name: car\n    base_uri: \"http://192.168.1.11:8086\"\n    client_numbers:\n      - 12222222222\n    commands:\n      - args:\n          - datatype: str\n            type: endpoint\n            index: 1\n          - datatype: int\n            path: price.current\n            type: json\n            index: 2\n            compress_rest: true\n        endpoint: /cars\n        method: put\n        pattern: .*changeprice.*\n        response:\n          type: json\n          success:\n            datatype: str\n            path: data\n          error:\n            datatype: str\n            path: data\n      - args:\n          - datatype: str\n            type: endpoint\n            index: 1\n        endpoint: /cars\n        method: delete\n        pattern: .*remove.*\n        response:\n          type: json\n          success:\n            datatype: str\n            path: data\n          error:\n            datatype: str\n            path: data\n```\n\nThe configuration above defines a single service. To send a command, a client number must\nsend a text to `11111111111` which COT polls from GVMS. Here, GVMS runs on `192.168.1.10`\nwith port `7777`. The single service, is represented by the command `car`.\n\nThe command `car` exposes two subcommands, one of which gets triggered when the user command\ncontains `changeprice` while the other gets triggered when the user command contains `remove`.\n\nThe first subcommand expects the user command to be `car changeprice [carname] price_1 price_2 ... price_n`.\nFrom the mapping, the raw command will be converted into a PUT request with the URL being\n`http://192.168.1.11:8086/cars/[carname]` with the payload being\n`{\"price\": {\"current\": [price_1, price_2, ..., price_n]}}`. The command will then return the contents of `data`\nkey from the response JSON payload.\n\nThe seconds subcommand expects the user command to be `car remove [carname]`. From the mapping, the raw command\nwill be converted into a DELETE request with the URL being `http://192.168.1.11:8086/cars/`. The command will\nthen return the contents of `data` key from the response JSON payload.\n\n#### **Reference**\n\nThe reference contains all of possible fields within `cot_sm.yaml`. The fields are represented by their path\nfrom the root of the config file. So, for example `gvms.hostname` will represent:\n\n```yaml\ngvms:\n  hostname:\n```\n\nIt is also important to know how COT does user command input parsing. COT parses the raw user input string into\ntokens that are split by space character. The first token corresponds to the service/base command name. The\nrest of the tokens correspond to args and are 0 indexed. When doing pattern patching of the command, the matching\nis done against the complete raw input, including the service/base command name.\n\n- **gvms.hostname** The hostname for GVMS.\n- **gvms.port** The port for GVMS.\n- **gvoice_number** The google voice number that client numbers need to send commands to\n  in order to be picked up by COT.\n- **services[].base_url** The base url used in the construction of an endpoint for a given service.\n- **services[].client_numbers[]** A list of client numbers that authorized for the client service. Each\n  client number must also include the country code.\n- **services[].commands[].endpoint** The endpoint that will be combined with the base_url to create the complete\n  the full path for a given comment.\n- **services[].commands[].method** The HTTP method to use for a given endpoint.\n- **services[].commands[].pattern** The regex pattern that is used to determine whether to run a command.\n  If a service has a single subcommand, this field can be skipped (regex `.*` will be applied).\n- **services[].commands[].args[].datatype** The datatype of the underlying arg. Supported types are as follows:\n  - For strings, either \"string\" or \"str\" are accepted.\n  - For integers, either \"integer\" or \"int\" are accepted.\n  - For decimals, either \"double\" or \"float\" are accepted.\n  - For booleans, either \"boolean\" or \"bool\" are accepted.\n- **services[].commands[].args[].type** The arg class. Supported arg classes are:\n  - For query args, use \"query\".\n  - For JSON args, use \"json\".\n  - For endpoint args, use \"endpoint\".\n- **services[].commands[].args[].index** The mapping between a raw arg and the current\n  translation.\n- **services[].commands[].args[].path** The JSON/query path to where place/get the arg. For endpoint args, this value\n  is ignored and can be removed.\n- **services[].commands[].args[].compress_rest** Whether to compress the rest of the input args from the current index\n  into an array of the given arg type.\n- **services[].commands[].response.type** The response content type. Supported types are:\n  - For JSON response content type, which will enable for further response parsing for success and error cases\n    use \"json\".\n  - To simply return the raw response, use \"plain_text\".\n- **services[].response.success** When type is set to \"json\", the path to retrieve the response content when\n  response status code is 200.\n- **services[].commands[].args[].filter** A filter list for accepted arg values. If not set. it is\n    assumed that all values are accepted for this arg.\n- **services[].response.error** When type is set to \"json\", the path to retrieve the response content when\n  response status code is not 200.\n\n### **Encryption Configuration**\n\nThe follow environment variables can be defined in the case were encryption is enabled. If\nencryption is not enabled, then none of these environment variables need to be set.\n\n- **COT_TEXT_ENCRYPTION=** whether encryption is enabled (true, false)\n- **COT_PUBLIC_KEY_FILE=** path to COT's public PGP key\n- **COT_PRIVATE_KEY_FILE=** path to COT's private PGP key\n- **COT_PASSPHRASE=** passphrase for COT's private PGP key\n- **COT_CN_PUBLIC_KEY_DIR=** directory that will store all of the client number public PGP keys\n- **COT_SIG_VERIFICATION=** whether signature verification is enabled for PGP\n- **COT_BASE64_ENCODING=** whether messages will be base64 encoded\n\n## **Installation**\n\n- Setup GVMS as explained [here](https://github.com/kingcobra2468/GVMS).\n- Clone COT and setup [configuration](#configuration).\n- Install dependencies with `go get`.\n- Launch COT with `go run main.go`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkingcobra2468%2Fcot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkingcobra2468%2Fcot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkingcobra2468%2Fcot/lists"}