osintengine 1.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- osintengine-1.0.2.dist-info/METADATA +311 -0
- osintengine-1.0.2.dist-info/RECORD +103 -0
- osintengine-1.0.2.dist-info/WHEEL +5 -0
- osintengine-1.0.2.dist-info/entry_points.txt +2 -0
- osintengine-1.0.2.dist-info/licenses/LICENSE +202 -0
- osintengine-1.0.2.dist-info/top_level.txt +2 -0
- src/watson/__init__.py +10 -0
- src/watson/agent/__init__.py +96 -0
- src/watson/agents/__init__.py +101 -0
- src/watson/agents/protocol.py +196 -0
- src/watson/auth/__init__.py +68 -0
- src/watson/auth/store.py +145 -0
- src/watson/conversation.py +68 -0
- src/watson/core/__init__.py +0 -0
- src/watson/core/models.py +96 -0
- src/watson/ethics.py +205 -0
- src/watson/exports.py +182 -0
- src/watson/graph/__init__.py +69 -0
- src/watson/graph/entities.py +207 -0
- src/watson/graph/graph.py +489 -0
- src/watson/graph/osint_framework.py +266 -0
- src/watson/graph/relationships.py +116 -0
- src/watson/graph/transforms.py +787 -0
- src/watson/infra/__init__.py +43 -0
- src/watson/infra/cache.py +171 -0
- src/watson/infra/ratelimit.py +125 -0
- src/watson/infra/resilience.py +239 -0
- src/watson/infra/retry.py +186 -0
- src/watson/metrics.py +128 -0
- src/watson/opsec/__init__.py +290 -0
- src/watson/orchestration/__init__.py +23 -0
- src/watson/orchestration/engine.py +5587 -0
- src/watson/orchestration/executor.py +96 -0
- src/watson/orchestration/intent.py +139 -0
- src/watson/orchestration/intent_classifier.py +45 -0
- src/watson/orchestration/llm_config.py +160 -0
- src/watson/orchestration/resolution.py +555 -0
- src/watson/orchestration/scraper.py +94 -0
- src/watson/orchestration/synthesis.py +726 -0
- src/watson/orchestration/target_profile.py +748 -0
- src/watson/persistence/__init__.py +18 -0
- src/watson/persistence/models.py +161 -0
- src/watson/persistence/store.py +230 -0
- src/watson/pipeline/__init__.py +16 -0
- src/watson/pipeline/pre_synthesis.py +621 -0
- src/watson/search.py +103 -0
- src/watson/serializers/stix.py +451 -0
- src/watson/tools/__init__.py +31 -0
- src/watson/tools/base.py +97 -0
- src/watson/tools/blockchain.py +359 -0
- src/watson/tools/captcha.py +276 -0
- src/watson/tools/conflict.py +107 -0
- src/watson/tools/corporate.py +287 -0
- src/watson/tools/darkweb.py +144 -0
- src/watson/tools/geolocation.py +347 -0
- src/watson/tools/image_video.py +108 -0
- src/watson/tools/marinetraffic.py +142 -0
- src/watson/tools/people.py +476 -0
- src/watson/tools/registry.py +56 -0
- src/watson/tools/satellite.py +118 -0
- src/watson/tools/scraper.py +745 -0
- src/watson/tools/shodan.py +129 -0
- src/watson/tools/social_media.py +160 -0
- src/watson/tools/websites.py +291 -0
- src/watson/tools/wikidata.py +398 -0
- src/watson/utils/__init__.py +1 -0
- src/watson/utils/helpers.py +49 -0
- src/watson/utils/http.py +119 -0
- src/watson/verification/__init__.py +245 -0
- watson/__init__.py +6 -0
- watson/agents/__init__.py +20 -0
- watson/agents/base.py +103 -0
- watson/agents/direct.py +225 -0
- watson/agents/hermes.py +275 -0
- watson/agents/hermes_mcp.py +292 -0
- watson/api_keys.py +176 -0
- watson/browser_scraper.py +481 -0
- watson/cli.py +836 -0
- watson/crossref.py +175 -0
- watson/ethics.py +20 -0
- watson/graph.py +406 -0
- watson/mcp_server.py +601 -0
- watson/memory.py +552 -0
- watson/neo4j_graph.py +124 -0
- watson/opsec/__init__.py +307 -0
- watson/reporter.py +537 -0
- watson/scheduler.py +486 -0
- watson/serializers/stix.py +451 -0
- watson/terminal.py +410 -0
- watson/toolkit.py +252 -0
- watson/toolkit_api.py +347 -0
- watson/toolkit_automation.py +95 -0
- watson/toolkit_registry.py +345 -0
- watson/verification/__init__.py +251 -0
- watson/web/__init__.py +1 -0
- watson/web/app.py +1650 -0
- watson/web/middleware.py +301 -0
- watson/web/static/assets/index-B7hPOc0z.js +278 -0
- watson/web/static/assets/index-CJ6FP8Mp.css +1 -0
- watson/web/static/assets/watson-logo-Dk9tawHb.png +0 -0
- watson/web/static/index.html +14 -0
- watson/web/templates/chat.html +2 -0
- watson/web/templates/investigation-map.html +429 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
"""OSINT Framework integration — maps 1,417 OSINT tools to Watson entity types.
|
|
2
|
+
|
|
3
|
+
The OSINT Framework (https://osintframework.com) is a curated tree of OSINT
|
|
4
|
+
tools organized by investigation target (username, email, domain, IP, etc.).
|
|
5
|
+
Maltego's competitive advantage is its Transform Hub — a marketplace of paid
|
|
6
|
+
data connectors. OSINT Framework is the open-source equivalent.
|
|
7
|
+
|
|
8
|
+
This module:
|
|
9
|
+
1. Loads the framework tree from cache (downloads on first use)
|
|
10
|
+
2. Maps framework categories to Watson entity types
|
|
11
|
+
3. Provides tool lookup by entity type (e.g., "what tools investigate domains?")
|
|
12
|
+
4. Generates search URLs for discovered entities (enrichment transforms)
|
|
13
|
+
|
|
14
|
+
Integration: when the graph engine discovers a new entity (e.g., a domain),
|
|
15
|
+
it queries OSINT Framework for relevant investigation tools, then enriches
|
|
16
|
+
findings with direct links to those tools — compensating for Watson's lack
|
|
17
|
+
of direct database access.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import json
|
|
23
|
+
import logging
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from typing import Optional
|
|
26
|
+
|
|
27
|
+
from .entities import EntityType
|
|
28
|
+
|
|
29
|
+
logger = logging.getLogger("watson.graph.osint_framework")
|
|
30
|
+
|
|
31
|
+
# Cache location
|
|
32
|
+
_CACHE_DIR = Path.home() / ".watson" / "cache"
|
|
33
|
+
_CACHE_FILE = _CACHE_DIR / "osint_framework.json"
|
|
34
|
+
_FRAMEWORK_URL = (
|
|
35
|
+
"https://raw.githubusercontent.com/lockfale/osint-framework/"
|
|
36
|
+
"master/public/arf.json"
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
# ── Category → EntityType mapping ─────────────────────────────────
|
|
40
|
+
# Maps OSINT Framework top-level categories to Watson entity types.
|
|
41
|
+
# When Watson discovers a Domain, it looks up the Domain category
|
|
42
|
+
# in the framework and gets all subcategory tools.
|
|
43
|
+
|
|
44
|
+
CATEGORY_ENTITY_MAP: dict[str, EntityType] = {
|
|
45
|
+
"Username": EntityType.PERSON,
|
|
46
|
+
"Email Address": EntityType.EMAIL,
|
|
47
|
+
"Domain Name": EntityType.DOMAIN,
|
|
48
|
+
"IP & MAC Address": EntityType.IP_ADDRESS,
|
|
49
|
+
"Images / Videos / Docs": EntityType.DOCUMENT,
|
|
50
|
+
"Social Networks": EntityType.PERSON,
|
|
51
|
+
"People Search Engines": EntityType.PERSON,
|
|
52
|
+
"Public Records": EntityType.PERSON,
|
|
53
|
+
"Business Records": EntityType.ORGANIZATION,
|
|
54
|
+
"Telephone Numbers": EntityType.PERSON,
|
|
55
|
+
"Geolocation Tools / Maps": EntityType.LOCATION,
|
|
56
|
+
"Cloud Infrastructure": EntityType.DOMAIN,
|
|
57
|
+
"Blockchain & Cryptocurrency": EntityType.ORGANIZATION,
|
|
58
|
+
"Dark Web": EntityType.DOCUMENT,
|
|
59
|
+
"Archives": EntityType.WEBSITE,
|
|
60
|
+
"Search Engines": EntityType.WEBSITE,
|
|
61
|
+
"Online Communities": EntityType.WEBSITE,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class OSINTFramework:
|
|
66
|
+
"""Query interface to the OSINT Framework tree."""
|
|
67
|
+
|
|
68
|
+
def __init__(self):
|
|
69
|
+
self._tree: dict = {}
|
|
70
|
+
self._loaded = False
|
|
71
|
+
self._by_entity_type: dict[EntityType, list[dict]] = {}
|
|
72
|
+
|
|
73
|
+
# ── Loading ──────────────────────────────────────────────────
|
|
74
|
+
|
|
75
|
+
def _ensure_loaded(self) -> None:
|
|
76
|
+
"""Load the framework tree from cache or download it."""
|
|
77
|
+
if self._loaded:
|
|
78
|
+
return
|
|
79
|
+
|
|
80
|
+
if _CACHE_FILE.exists():
|
|
81
|
+
try:
|
|
82
|
+
self._tree = json.loads(_CACHE_FILE.read_text())
|
|
83
|
+
self._loaded = True
|
|
84
|
+
self._build_index()
|
|
85
|
+
logger.info(
|
|
86
|
+
"osint_framework_loaded_from_cache: %s",
|
|
87
|
+
_CACHE_FILE,
|
|
88
|
+
)
|
|
89
|
+
return
|
|
90
|
+
except (json.JSONDecodeError, OSError):
|
|
91
|
+
logger.warning("osint_framework_cache_corrupt, re-downloading")
|
|
92
|
+
|
|
93
|
+
self._download()
|
|
94
|
+
self._loaded = True
|
|
95
|
+
self._build_index()
|
|
96
|
+
|
|
97
|
+
def _download(self) -> None:
|
|
98
|
+
"""Download the framework data from GitHub."""
|
|
99
|
+
import urllib.request
|
|
100
|
+
|
|
101
|
+
logger.info("osint_framework_downloading: %s", _FRAMEWORK_URL)
|
|
102
|
+
try:
|
|
103
|
+
_CACHE_DIR.mkdir(parents=True, exist_ok=True)
|
|
104
|
+
urllib.request.urlretrieve(_FRAMEWORK_URL, str(_CACHE_FILE))
|
|
105
|
+
self._tree = json.loads(_CACHE_FILE.read_text())
|
|
106
|
+
logger.info(
|
|
107
|
+
"osint_framework_downloaded: %d top-level nodes",
|
|
108
|
+
len(self._tree.get("children", [])),
|
|
109
|
+
)
|
|
110
|
+
except Exception as e:
|
|
111
|
+
logger.error("osint_framework_download_failed: %s", e)
|
|
112
|
+
self._tree = {"name": "OSINT Framework", "type": "folder", "children": []}
|
|
113
|
+
|
|
114
|
+
def _build_index(self) -> None:
|
|
115
|
+
"""Build entity-type lookup index from the tree."""
|
|
116
|
+
self._by_entity_type = {}
|
|
117
|
+
|
|
118
|
+
root_children = self._tree.get("children", [])
|
|
119
|
+
for category in root_children:
|
|
120
|
+
cat_name = category.get("name", "")
|
|
121
|
+
entity_type = CATEGORY_ENTITY_MAP.get(cat_name)
|
|
122
|
+
if entity_type is None:
|
|
123
|
+
continue
|
|
124
|
+
|
|
125
|
+
tools = self._extract_tools(category)
|
|
126
|
+
if tools:
|
|
127
|
+
existing = self._by_entity_type.setdefault(entity_type, [])
|
|
128
|
+
existing.extend(tools)
|
|
129
|
+
|
|
130
|
+
# Log what we mapped
|
|
131
|
+
for et, tools in self._by_entity_type.items():
|
|
132
|
+
logger.info(
|
|
133
|
+
"osint_framework_mapped: %s → %d tools",
|
|
134
|
+
et.value,
|
|
135
|
+
len(tools),
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
def _extract_tools(self, node: dict, parent_category: str = "") -> list[dict]:
|
|
139
|
+
"""Recursively extract tool entries from a framework node."""
|
|
140
|
+
tools: list[dict] = []
|
|
141
|
+
|
|
142
|
+
node_type = node.get("type", "")
|
|
143
|
+
name = node.get("name", "")
|
|
144
|
+
url = node.get("url", "")
|
|
145
|
+
|
|
146
|
+
if node_type != "folder" and url:
|
|
147
|
+
# This is a leaf tool entry
|
|
148
|
+
tools.append({
|
|
149
|
+
"name": name,
|
|
150
|
+
"url": url,
|
|
151
|
+
"category": parent_category or name,
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
for child in node.get("children", []):
|
|
155
|
+
child_category = name if node_type == "folder" else parent_category
|
|
156
|
+
tools.extend(self._extract_tools(child, child_category))
|
|
157
|
+
|
|
158
|
+
return tools
|
|
159
|
+
|
|
160
|
+
# ── Query API ────────────────────────────────────────────────
|
|
161
|
+
|
|
162
|
+
def get_tools_for_entity(self, entity_type: EntityType) -> list[dict]:
|
|
163
|
+
"""Return all OSINT Framework tools relevant to an entity type.
|
|
164
|
+
|
|
165
|
+
Example:
|
|
166
|
+
>>> framework.get_tools_for_entity(EntityType.DOMAIN)
|
|
167
|
+
[
|
|
168
|
+
{"name": "Domain Dossier", "url": "https://centralops.net/...",
|
|
169
|
+
"category": "Whois Records"},
|
|
170
|
+
{"name": "Shodan", "url": "https://www.shodan.io/",
|
|
171
|
+
"category": "Discovery"},
|
|
172
|
+
...
|
|
173
|
+
]
|
|
174
|
+
"""
|
|
175
|
+
self._ensure_loaded()
|
|
176
|
+
return self._by_entity_type.get(entity_type, [])
|
|
177
|
+
|
|
178
|
+
def get_search_urls(
|
|
179
|
+
self,
|
|
180
|
+
entity_type: EntityType,
|
|
181
|
+
value: str,
|
|
182
|
+
max_results: int = 10,
|
|
183
|
+
) -> list[dict]:
|
|
184
|
+
"""Generate ready-to-use search URLs for an entity.
|
|
185
|
+
|
|
186
|
+
Takes OSINT Framework tools and interpolates the entity value
|
|
187
|
+
into their search URL templates (where the tool supports it).
|
|
188
|
+
For tools that don't have search URL templates, returns the
|
|
189
|
+
tool homepage as a reference link.
|
|
190
|
+
|
|
191
|
+
Returns list of {"tool": str, "url": str, "category": str}.
|
|
192
|
+
"""
|
|
193
|
+
self._ensure_loaded()
|
|
194
|
+
tools = self.get_tools_for_entity(entity_type)
|
|
195
|
+
results: list[dict] = []
|
|
196
|
+
|
|
197
|
+
for tool in tools[:max_results]:
|
|
198
|
+
url = tool["url"]
|
|
199
|
+
name = tool["name"]
|
|
200
|
+
|
|
201
|
+
# Interpolate search parameters where supported
|
|
202
|
+
if "<%3C" in url or "%3C" in url:
|
|
203
|
+
# Has a template parameter — interpolate the entity value
|
|
204
|
+
url = url.replace("<%3Cusername%3E>", value)
|
|
205
|
+
url = url.replace("<%3Cdomain%3E>", value)
|
|
206
|
+
url = url.replace("<%3Cemail%3E>", value)
|
|
207
|
+
url = url.replace("<%3Cip%3E>", value)
|
|
208
|
+
|
|
209
|
+
results.append({
|
|
210
|
+
"tool": name,
|
|
211
|
+
"url": url,
|
|
212
|
+
"category": tool.get("category", ""),
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
return results
|
|
216
|
+
|
|
217
|
+
def get_categories(self) -> list[str]:
|
|
218
|
+
"""Return all top-level OSINT Framework categories."""
|
|
219
|
+
self._ensure_loaded()
|
|
220
|
+
return [
|
|
221
|
+
c.get("name", "")
|
|
222
|
+
for c in self._tree.get("children", [])
|
|
223
|
+
]
|
|
224
|
+
|
|
225
|
+
def search_tools(self, keyword: str, limit: int = 20) -> list[dict]:
|
|
226
|
+
"""Search all tools by keyword (case-insensitive)."""
|
|
227
|
+
self._ensure_loaded()
|
|
228
|
+
keyword_lower = keyword.lower()
|
|
229
|
+
results: list[dict] = []
|
|
230
|
+
|
|
231
|
+
def _search(node):
|
|
232
|
+
name = node.get("name", "")
|
|
233
|
+
if keyword_lower in name.lower():
|
|
234
|
+
url = node.get("url", "")
|
|
235
|
+
if url:
|
|
236
|
+
results.append({"name": name, "url": url})
|
|
237
|
+
for child in node.get("children", []):
|
|
238
|
+
_search(child)
|
|
239
|
+
|
|
240
|
+
_search(self._tree)
|
|
241
|
+
return results[:limit]
|
|
242
|
+
|
|
243
|
+
@property
|
|
244
|
+
def total_tools(self) -> int:
|
|
245
|
+
"""Total number of tool entries in the framework."""
|
|
246
|
+
self._ensure_loaded()
|
|
247
|
+
|
|
248
|
+
def _count(node):
|
|
249
|
+
if node.get("type") != "folder" and node.get("url"):
|
|
250
|
+
return 1
|
|
251
|
+
return sum(_count(c) for c in node.get("children", []))
|
|
252
|
+
|
|
253
|
+
return _count(self._tree)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
# ── Singleton ─────────────────────────────────────────────────────
|
|
257
|
+
|
|
258
|
+
_framework_instance: Optional[OSINTFramework] = None
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def get_framework() -> OSINTFramework:
|
|
262
|
+
"""Get or create the singleton OSINT Framework instance."""
|
|
263
|
+
global _framework_instance
|
|
264
|
+
if _framework_instance is None:
|
|
265
|
+
_framework_instance = OSINTFramework()
|
|
266
|
+
return _framework_instance
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""Typed relationships for the Watson entity graph.
|
|
2
|
+
|
|
3
|
+
Each relationship connects two entities and carries metadata about how
|
|
4
|
+
the connection was discovered (source transform, confidence, timestamp).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass, field
|
|
10
|
+
from datetime import datetime, timezone
|
|
11
|
+
from enum import Enum
|
|
12
|
+
from typing import ClassVar
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class RelationshipType(str, Enum):
|
|
16
|
+
"""Standard OSINT relationship types — mirrors Maltego's link labels."""
|
|
17
|
+
# Infrastructure
|
|
18
|
+
RESOLVES_TO = "resolves_to" # Domain → IPAddress
|
|
19
|
+
HAS_SUBDOMAIN = "has_subdomain" # Domain → Domain
|
|
20
|
+
HOSTED_ON = "hosted_on" # Website → IPAddress
|
|
21
|
+
USES_NAMESERVER = "uses_nameserver" # Domain → Domain (NS record)
|
|
22
|
+
|
|
23
|
+
# People & Organizations
|
|
24
|
+
HAS_EMAIL = "has_email" # Domain/Person → Email
|
|
25
|
+
WORKS_AT = "works_at" # Person → Organization
|
|
26
|
+
OWNS = "owns" # Person → Domain/Website
|
|
27
|
+
CONTACT_FOR = "contact_for" # Email → Organization (role-based)
|
|
28
|
+
|
|
29
|
+
# Location
|
|
30
|
+
LOCATED_IN = "located_in" # IPAddress → Location
|
|
31
|
+
BASED_IN = "based_in" # Organization → Location
|
|
32
|
+
REGISTERED_IN = "registered_in" # Domain → Location
|
|
33
|
+
|
|
34
|
+
# Content
|
|
35
|
+
MENTIONS = "mentions" # Website/Document → Entity
|
|
36
|
+
CONTAINS = "contains" # Document → Entity (extracted)
|
|
37
|
+
REFERENCES = "references" # Website → Website/Document
|
|
38
|
+
|
|
39
|
+
# Generic
|
|
40
|
+
RELATED_TO = "related_to" # Any → Any (fallback)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass
|
|
44
|
+
class Relationship:
|
|
45
|
+
"""A directed, typed link between two entities."""
|
|
46
|
+
|
|
47
|
+
source_id: str # Entity ID of the source node
|
|
48
|
+
target_id: str # Entity ID of the target node
|
|
49
|
+
rel_type: RelationshipType
|
|
50
|
+
confidence: float = field(default=0.7, metadata={"ge": 0.0, "le": 1.0})
|
|
51
|
+
source_transform: str = "" # Which transform created this
|
|
52
|
+
evidence: list[str] = field(default_factory=list) # Source URLs/proof
|
|
53
|
+
created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
|
|
54
|
+
properties: dict = field(default_factory=dict)
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def id(self) -> str:
|
|
58
|
+
"""Unique relationship ID."""
|
|
59
|
+
raw = f"{self.source_id}:{self.rel_type.value}:{self.target_id}"
|
|
60
|
+
import hashlib
|
|
61
|
+
return hashlib.sha256(raw.encode()).hexdigest()[:16]
|
|
62
|
+
|
|
63
|
+
def __hash__(self) -> int:
|
|
64
|
+
return hash(self.id)
|
|
65
|
+
|
|
66
|
+
def __eq__(self, other: object) -> bool:
|
|
67
|
+
if not isinstance(other, Relationship):
|
|
68
|
+
return False
|
|
69
|
+
return self.id == other.id
|
|
70
|
+
|
|
71
|
+
def to_dict(self) -> dict:
|
|
72
|
+
return {
|
|
73
|
+
"id": self.id,
|
|
74
|
+
"source_id": self.source_id,
|
|
75
|
+
"target_id": self.target_id,
|
|
76
|
+
"rel_type": self.rel_type.value,
|
|
77
|
+
"confidence": self.confidence,
|
|
78
|
+
"source_transform": self.source_transform,
|
|
79
|
+
"evidence": self.evidence,
|
|
80
|
+
"properties": self.properties,
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
def __repr__(self) -> str:
|
|
84
|
+
return (
|
|
85
|
+
f"Relationship({self.source_id[:8]} "
|
|
86
|
+
f"-{self.rel_type.value}→ "
|
|
87
|
+
f"{self.target_id[:8]})"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
# ── Shorthand aliases for readability ─────────────────────────────
|
|
92
|
+
|
|
93
|
+
# Infrastructure
|
|
94
|
+
RESOLVES_TO = RelationshipType.RESOLVES_TO
|
|
95
|
+
HAS_SUBDOMAIN = RelationshipType.HAS_SUBDOMAIN
|
|
96
|
+
HOSTED_ON = RelationshipType.HOSTED_ON
|
|
97
|
+
USES_NAMESERVER = RelationshipType.USES_NAMESERVER
|
|
98
|
+
|
|
99
|
+
# People & Organizations
|
|
100
|
+
HAS_EMAIL = RelationshipType.HAS_EMAIL
|
|
101
|
+
WORKS_AT = RelationshipType.WORKS_AT
|
|
102
|
+
OWNS = RelationshipType.OWNS
|
|
103
|
+
CONTACT_FOR = RelationshipType.CONTACT_FOR
|
|
104
|
+
|
|
105
|
+
# Location
|
|
106
|
+
LOCATED_IN = RelationshipType.LOCATED_IN
|
|
107
|
+
BASED_IN = RelationshipType.BASED_IN
|
|
108
|
+
REGISTERED_IN = RelationshipType.REGISTERED_IN
|
|
109
|
+
|
|
110
|
+
# Content
|
|
111
|
+
MENTIONS = RelationshipType.MENTIONS
|
|
112
|
+
CONTAINS = RelationshipType.CONTAINS
|
|
113
|
+
REFERENCES = RelationshipType.REFERENCES
|
|
114
|
+
|
|
115
|
+
# Generic
|
|
116
|
+
RELATED_TO = RelationshipType.RELATED_TO
|