{"id":19883677,"url":"https://github.com/muchdogesec/location2stix","last_synced_at":"2025-08-07T02:14:32.092Z","repository":{"id":244184121,"uuid":"813493396","full_name":"muchdogesec/location2stix","owner":"muchdogesec","description":"A command line tool that converts Countries and Regions into STIX 2.1 Location objects with rich relationships","archived":false,"fork":false,"pushed_at":"2025-06-26T08:13:30.000Z","size":593,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-06-26T09:27:27.397Z","etag":null,"topics":["iso-3166","stix2"],"latest_commit_sha":null,"homepage":"https://www.dogesec.com/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/muchdogesec.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2024-06-11T07:38:47.000Z","updated_at":"2025-06-26T08:13:31.000Z","dependencies_parsed_at":"2024-06-13T09:57:01.633Z","dependency_job_id":"6665d5e8-fae9-48cb-8e9c-7a8354a900ba","html_url":"https://github.com/muchdogesec/location2stix","commit_stats":null,"previous_names":["muchdogesec/location2stix"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/muchdogesec/location2stix","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/muchdogesec%2Flocation2stix","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/muchdogesec%2Flocation2stix/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/muchdogesec%2Flocation2stix/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/muchdogesec%2Flocation2stix/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/muchdogesec","download_url":"https://codeload.github.com/muchdogesec/location2stix/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/muchdogesec%2Flocation2stix/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269185726,"owners_count":24374634,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-07T02:00:09.698Z","response_time":73,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["iso-3166","stix2"],"created_at":"2024-11-12T17:21:59.813Z","updated_at":"2025-08-07T02:14:32.070Z","avatar_url":"https://github.com/muchdogesec.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# location2stix\n\nA command line tool that converts Countries and Regions into STIX 2.1 Location objects with rich relationships\n\n## Before you begin\n\nWe host a full web API that includes all objects created by location2stix, [CTIButler](https://www.ctibutler.com/).\n\n## Overview\n\n![](docs/location2stix.png)\n\nThe STIX Location object allows you to map location from country level all the way down to an exact address or latitude / longitude pair.\n\nThe problem is, many locations (e.g. a Country) are unique. The way Location SDOs are generated (using a random UUID v4) means that two different intelligence producers will create a STIX Location object with a different `id` for exactly the same place.\n\nFor intelligence reporting, there are times a specific address or lat/lon pair is used. However, more generally intelligence is reported at a regional or country level (e.g. North Korea actors targeting financial institutions in the United States).\n\nThis code is designed to map UN Regions, Groupings of Countries and Countries themselves as STIX objects so that they can be used freely by intelligence producers when working with location related intelligence.\n\nWe use ISO 3166 to generate this data, you can see this data in the `ISO-3166-Countries-with-Regional-Codes.csv` in the `input_data` directory of this repository.\n\n## tl;dr\n\n[![stix2arango](https://img.youtube.com/vi/lMmAi9FveC0/0.jpg)](https://www.youtube.com/watch?v=lMmAi9FveC0)\n\n[Watch the demo](https://www.youtube.com/watch?v=lMmAi9FveC0).\n\n## Install the script\n\n```shell\n# clone the latest code\ngit clone https://github.com/muchdogesec/location2stix\n# create a venv\ncd location2stix\npython3 -m venv location2stix-venv\nsource location2stix-venv/bin/activate\n# install requirements\npip3 install -r requirements.txt\n```\n\n## Usage\n\n```shell\npython3 location2stix.py\n```\n\n## STIX Mappings\n\n### A note on the STIX2 filestore\n\nThis script uses the STIX2 Python libraries filestore feature.\n\nAll objects created are stored in the directory `stix2objects`.\n\nOn each run, this directory is deleted, and the object regenerated.\n\n### Marking Definition / Identity\n\nThese are hard-coded and imported from our [stix4doge repository](https://github.com/muchdogesec/stix4doge). Specifically these objects;\n\n* Marking Definition: https://raw.githubusercontent.com/muchdogesec/stix4doge/main/objects/marking-definition/location2stix.json\n* Identity: https://raw.githubusercontent.com/muchdogesec/stix4doge/main/objects/identity/location2stix.json\n\n### Country Level Data\n\nEach country object is mapped to a STIX location object as follows;\n\n```json\n{\n\t\"type\": \"location\",\n\t\"spec_version\": \"2.1\",\n\t\"id\": \"location--\u003cUUID V5\u003e\",\n\t\"created_by_ref\": \"identity--\u003cIMPORTED IDENTITY\u003e\",\n\t\"created\": \"2020-01-01T00:00:00.000Z\",\n\t\"modified\": \"2020-01-01T00:00:00.000Z\",\n\t\"name\": \"\u003cname\u003e\",\n\t\"region\": \"\u003cCONVERTED SUBREGION\u003e\",\n\t\"country\": \"\u003calpha-2\u003e\",\n\t\"object_marking_refs\": [\n        \"marking-definition--94868c89-83c2-464b-929b-a1a8aa3c8487\",\n        \"\u003cIMPORTED MARKING DEFINITION\u003e\"\n    ],\n    \"external_references\": [\n        {\n            \"source_name\": \"type\",\n            \"external_id\": \"\u003ceither county/region/sub-region/intermediate-region\u003e\"\n        },\n        {\n            \"source_name\": \"alpha-2\",\n            \"external_id\": \"\u003calpha-2\u003e\"\n        },\n        {\n            \"source_name\": \"alpha-3\",\n            \"external_id\": \"\u003calpha-3\u003e\"\n        },\n        {\n            \"source_name\": \"iso_3166-2\",\n            \"external_id\": \"\u003ciso_3166-2\u003e\"\n        },\n        {\n            \"source_name\": \"country-code\",\n            \"external_id\": \"\u003ccountry-code\u003e\"\n        },\n        {\n            \"source_name\": \"location2stix\",\n            \"external_id\": \"\u003calpha-2\u003e\"\n        }\n    ]\n}\n```\n\nThe UUIDv5 is generated using the namespace `674a16c1-8b43-5c3e-8692-b3d8935e4903` with the `name`.\n\ne.g. `674a16c1-8b43-5c3e-8692-b3d8935e4903` `France` = `location--4e9a8b79-6776-56e3-b72c-cb19a086b6a8`\n\n`\u003cCONVERTED SUBREGION\u003e` must match entry from `region-ov`: https://docs.oasis-open.org/cti/stix/v2.1/os/stix-v2.1-os.html#_i1sw27qw1v0s. To turn the JSON response into a valid option in this list, the subregion value found in the csv file is first:\n\n* made lower case\n* any whitespaces replaced with `-`\n* the string ` and` is removed\n\n### Intermediate regions\n\nFor every distinct sub-region in the csv, a sub-region object is created\n\n```json\n{\n\t\"type\": \"location\",\n\t\"spec_version\": \"2.1\",\n\t\"id\": \"location--\u003cUUID V5\u003e\",\n\t\"created_by_ref\": \"identity--\u003cIMPORTED IDENTITY\u003e\",\n\t\"created\": \"2020-01-01T00:00:00.000Z\",\n\t\"modified\": \"2020-01-01T00:00:00.000Z\",\n\t\"name\": \"\u003cintermediate-region\u003e\",\n\t\"region\": \"\u003cCONVERTED intermediate-region\u003e\",\n\t\"object_marking_refs\": [\n        \"marking-definition--94868c89-83c2-464b-929b-a1a8aa3c8487\",\n        \"\u003cIMPORTED MARKING DEFINITION\u003e\"\n    ],\n    \"external_references\": [\n        {\n            \"source_name\": \"intermediate-region-code\",\n            \"external_id\": \"\u003cintermediate-region-code\u003e\"\n        },\n        {\n            \"source_name\": \"location2stix\",\n            \"external_id\": \"\u003cCONVERTED intermediate-region\u003e\"\n        }\n    ]\n}\n```\n\nThe UUIDv5 is generated using the namespace `674a16c1-8b43-5c3e-8692-b3d8935e4903` with the `name`.\n\n### Sub-regions\n\nFor every distinct sub-region in the csv, a sub-region object is created\n\n```json\n{\n\t\"type\": \"location\",\n\t\"spec_version\": \"2.1\",\n\t\"id\": \"location--\u003cUUID V5\u003e\",\n\t\"created_by_ref\": \"identity--\u003cIMPORTED IDENTITY\u003e\",\n\t\"created\": \"2020-01-01T00:00:00.000Z\",\n\t\"modified\": \"2020-01-01T00:00:00.000Z\",\n\t\"name\": \"\u003csub-region\u003e\",\n\t\"region\": \"\u003cCONVERTED sub-region\u003e\",\n\t\"object_marking_refs\": [\n        \"marking-definition--94868c89-83c2-464b-929b-a1a8aa3c8487\",\n        \"\u003cIMPORTED MARKING DEFINITION\u003e\"\n    ],\n    \"external_references\": [\n        {\n            \"source_name\": \"sub-region-code\",\n            \"external_id\": \"\u003csub-region-code\u003e\"\n        },\n        {\n            \"source_name\": \"location2stix\",\n            \"external_id\": \"\u003cCONVERTED sub-region\u003e\"\n        }\n    ]\n}\n```\n\nThe UUIDv5 is generated using the namespace `674a16c1-8b43-5c3e-8692-b3d8935e4903` with the `name`.\n\n### Region\n\n```json\n{\n\t\"type\": \"location\",\n\t\"spec_version\": \"2.1\",\n\t\"id\": \"location--\u003cUUID V5\u003e\",\n\t\"created_by_ref\": \"identity--\u003cIMPORTED IDENTITY\u003e\",\n\t\"created\": \"2020-01-01T00:00:00.000Z\",\n\t\"modified\": \"2020-01-01T00:00:00.000Z\",\n\t\"name\": \"\u003cregion\u003e\",\n\t\"region\": \"\u003cCONVERTED region\u003e\",\n\t\"object_marking_refs\": [\n        \"marking-definition--94868c89-83c2-464b-929b-a1a8aa3c8487\",\n        \"\u003cIMPORTED MARKING DEFINITION\u003e\"\n    ],\n    \"external_references\": [\n        {\n            \"source_name\": \"region-code\",\n            \"external_id\": \"\u003cregion-code\u003e\"\n        },\n        {\n            \"source_name\": \"location2stix\",\n            \"external_id\": \"\u003cCONVERTED region\u003e\"\n        }\n    ]\n}\n```\n\n### Relationships\n\n1. Sub-regions (`source_ref`) have a relationship to a Regions (`target_ref`) (type: `region`)\n2. Intermediate-regions (`source_ref`) have a relationship to Sub-regions (`target_ref`) (type: `sub-region`)\n3. Countries (`source_ref`) have a relationship to a Sub-region (`target_ref`) (type: `sub-region`)\n4. Countries (`source_ref`) have a relationship to a Region (`target_ref`) (type: `region`)\n5. Countries (`source_ref`) have a relationship to a Intermediate-Region (`target_ref`) (type: `intermediate-region`)\n\n\u003ciframe width=\"768\" height=\"432\" src=\"https://miro.com/app/live-embed/uXjVKAj06DQ=/?moveToViewport=-653,-302,761,366\u0026embedId=10658975368\" frameborder=\"0\" scrolling=\"no\" allow=\"fullscreen; clipboard-read; clipboard-write\" allowfullscreen\u003e\u003c/iframe\u003e\n\nFor each of these relationships, a STIX SRO is created as follows\n\n```json\n{\n    \"type\": \"relationship\",\n    \"spec_version\": \"2.1\",\n    \"id\": \"relationship--\u003cUUID V5\u003e\",\n    \"created_by_ref\": \"\u003cIMPORTED IDENTITY\u003e\",\n    \"created\": \"2020-01-01T00:00:00.000Z\",\n    \"modified\": \"2020-01-01T00:00:00.000Z\",\n    \"description\": \"\u003cSOURCE.NAME\u003e belongs to the \u003cTYPE\u003e of \u003cTARGET\u003e\",\n    \"relationship_type\": \"\u003cTYPE\u003e\",\n    \"source_ref\": \"\u003cSOURCE\u003e\",\n    \"target_ref\": \"\u003cTARGET\u003e\",\n    \"object_marking_refs\": [\n        \"marking-definition--94868c89-83c2-464b-929b-a1a8aa3c8487\",\n        \"\u003cIMPORTED MARKING DEFINITION\u003e\"\n    ]\n}\n```\n\nThe UUIDv5 is generated using the namespace `674a16c1-8b43-5c3e-8692-b3d8935e4903` and `source_ref` + `target_ref`\n\ne.g. `674a16c1-8b43-5c3e-8692-b3d8935e4903` `location--c42e841b-8ec7-422a-ac10-2704930291d4+location--a19a2293-6f58-435a-a41c-c8830e43eef4` == `relationship--725fcf9b-3e13-5990-8410-2ad7028437ba`\n\n### Bundle\n\nA bundle containing all objects is then created:\n\n```json\n{\n    \"type\": \"bundle\",\n    \"id\": \"bundle--\u003cUUID V5\u003e\",\n    \"objects\": [\n        \"\u003cALL STIX OBJECTS\u003e\"\n    ]\n}\n```\n\nThe UUIDv5 is generated using the namespace `674a16c1-8b43-5c3e-8692-b3d8935e4903` with the value being the MD5 has of all objects sorted in the bundle.\n\nThe name of the output bundle is `locations-bundle.json` and is stored in the `stix2objects` directory.\n\n## Useful supporting tools\n\n* To generate STIX 2.1 Objects: [stix2 Python Lib](https://stix2.readthedocs.io/en/latest/)\n* The STIX 2.1 specification: [STIX 2.1 docs](https://docs.oasis-open.org/cti/stix/v2.1/stix-v2.1.html)\n\n## Support\n\n[Minimal support provided via the DOGESEC community](https://community.dogesec.com/).\n\n## License\n\n[Apache 2.0](/LICENSE).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmuchdogesec%2Flocation2stix","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmuchdogesec%2Flocation2stix","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmuchdogesec%2Flocation2stix/lists"}