mirror of
https://github.com/domainaware/parsedmarc.git
synced 2026-05-04 02:55:26 +00:00
Update docs
This commit is contained in:
+2
-2
@@ -5,14 +5,14 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Overview: module code — parsedmarc 9.10.0 documentation</title>
|
||||
<title>Overview: module code — parsedmarc 9.10.2 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="../_static/css/theme.css?v=e59714d7" />
|
||||
|
||||
|
||||
<script src="../_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="../_static/documentation_options.js?v=3c16008f"></script>
|
||||
<script src="../_static/documentation_options.js?v=af960efc"></script>
|
||||
<script src="../_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="../_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="../_static/js/theme.js"></script>
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>parsedmarc — parsedmarc 9.10.0 documentation</title>
|
||||
<title>parsedmarc — parsedmarc 9.10.2 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="../_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="../_static/css/theme.css?v=e59714d7" />
|
||||
|
||||
|
||||
<script src="../_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="../_static/documentation_options.js?v=3c16008f"></script>
|
||||
<script src="../_static/documentation_options.js?v=af960efc"></script>
|
||||
<script src="../_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="../_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="../_static/js/theme.js"></script>
|
||||
@@ -129,6 +129,7 @@
|
||||
<span class="n">GmailConnection</span><span class="p">,</span>
|
||||
<span class="n">IMAPConnection</span><span class="p">,</span>
|
||||
<span class="n">MailboxConnection</span><span class="p">,</span>
|
||||
<span class="n">MaildirConnection</span><span class="p">,</span>
|
||||
<span class="n">MSGraphConnection</span><span class="p">,</span>
|
||||
<span class="p">)</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">parsedmarc.types</span><span class="w"> </span><span class="kn">import</span> <span class="p">(</span>
|
||||
@@ -2185,6 +2186,9 @@
|
||||
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">connection</span><span class="p">,</span> <span class="n">MSGraphConnection</span><span class="p">):</span>
|
||||
<span class="n">message_id</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">msg_uid</span><span class="p">)</span>
|
||||
<span class="n">msg_content</span> <span class="o">=</span> <span class="n">connection</span><span class="o">.</span><span class="n">fetch_message</span><span class="p">(</span><span class="n">message_id</span><span class="p">,</span> <span class="n">mark_read</span><span class="o">=</span><span class="ow">not</span> <span class="n">test</span><span class="p">)</span>
|
||||
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">connection</span><span class="p">,</span> <span class="n">MaildirConnection</span><span class="p">):</span>
|
||||
<span class="n">message_id</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">msg_uid</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">msg_uid</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span> <span class="k">else</span> <span class="n">msg_uid</span>
|
||||
<span class="n">msg_content</span> <span class="o">=</span> <span class="n">connection</span><span class="o">.</span><span class="n">fetch_message</span><span class="p">(</span><span class="n">message_id</span><span class="p">,</span> <span class="n">mark_read</span><span class="o">=</span><span class="ow">not</span> <span class="n">test</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">message_id</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">msg_uid</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">msg_uid</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span> <span class="k">else</span> <span class="n">msg_uid</span>
|
||||
<span class="n">msg_content</span> <span class="o">=</span> <span class="n">connection</span><span class="o">.</span><span class="n">fetch_message</span><span class="p">(</span><span class="n">message_id</span><span class="p">)</span>
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>parsedmarc.elastic — parsedmarc 9.10.0 documentation</title>
|
||||
<title>parsedmarc.elastic — parsedmarc 9.10.2 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/css/theme.css?v=e59714d7" />
|
||||
|
||||
|
||||
<script src="../../_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="../../_static/documentation_options.js?v=3c16008f"></script>
|
||||
<script src="../../_static/documentation_options.js?v=af960efc"></script>
|
||||
<script src="../../_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="../../_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="../../_static/js/theme.js"></script>
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>parsedmarc.opensearch — parsedmarc 9.10.0 documentation</title>
|
||||
<title>parsedmarc.opensearch — parsedmarc 9.10.2 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/css/theme.css?v=e59714d7" />
|
||||
|
||||
|
||||
<script src="../../_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="../../_static/documentation_options.js?v=3c16008f"></script>
|
||||
<script src="../../_static/documentation_options.js?v=af960efc"></script>
|
||||
<script src="../../_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="../../_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="../../_static/js/theme.js"></script>
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>parsedmarc.splunk — parsedmarc 9.10.0 documentation</title>
|
||||
<title>parsedmarc.splunk — parsedmarc 9.10.2 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/css/theme.css?v=e59714d7" />
|
||||
|
||||
|
||||
<script src="../../_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="../../_static/documentation_options.js?v=3c16008f"></script>
|
||||
<script src="../../_static/documentation_options.js?v=af960efc"></script>
|
||||
<script src="../../_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="../../_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="../../_static/js/theme.js"></script>
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>parsedmarc.types — parsedmarc 9.10.0 documentation</title>
|
||||
<title>parsedmarc.types — parsedmarc 9.10.2 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/css/theme.css?v=e59714d7" />
|
||||
|
||||
|
||||
<script src="../../_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="../../_static/documentation_options.js?v=3c16008f"></script>
|
||||
<script src="../../_static/documentation_options.js?v=af960efc"></script>
|
||||
<script src="../../_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="../../_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="../../_static/js/theme.js"></script>
|
||||
|
||||
+50
-203
@@ -5,14 +5,14 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>parsedmarc.utils — parsedmarc 9.10.0 documentation</title>
|
||||
<title>parsedmarc.utils — parsedmarc 9.10.2 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="../../_static/css/theme.css?v=e59714d7" />
|
||||
|
||||
|
||||
<script src="../../_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="../../_static/documentation_options.js?v=3c16008f"></script>
|
||||
<script src="../../_static/documentation_options.js?v=af960efc"></script>
|
||||
<script src="../../_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="../../_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="../../_static/js/theme.js"></script>
|
||||
@@ -98,7 +98,6 @@
|
||||
<span class="kn">import</span><span class="w"> </span><span class="nn">shutil</span>
|
||||
<span class="kn">import</span><span class="w"> </span><span class="nn">subprocess</span>
|
||||
<span class="kn">import</span><span class="w"> </span><span class="nn">tempfile</span>
|
||||
<span class="kn">import</span><span class="w"> </span><span class="nn">time</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">datetime</span><span class="w"> </span><span class="kn">import</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">timedelta</span><span class="p">,</span> <span class="n">timezone</span>
|
||||
<span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Optional</span><span class="p">,</span> <span class="n">TypedDict</span><span class="p">,</span> <span class="n">Union</span><span class="p">,</span> <span class="n">cast</span>
|
||||
|
||||
@@ -599,31 +598,18 @@
|
||||
|
||||
|
||||
|
||||
<span class="c1"># IPinfo Lite REST API. When ``_IPINFO_API_TOKEN`` is set, ``get_ip_address_db_record()``</span>
|
||||
<span class="c1"># queries the API first and falls through to the bundled/cached MMDB only on</span>
|
||||
<span class="c1"># rate-limit/quota/network errors. A 401/403 on any lookup propagates as</span>
|
||||
<span class="c1"># ``InvalidIPinfoAPIKey`` so the CLI exits fatally; callers of the library</span>
|
||||
<span class="c1"># should catch it.</span>
|
||||
<span class="c1"># IPinfo Lite REST API. When ``_IPINFO_API_TOKEN`` is set,</span>
|
||||
<span class="c1"># ``get_ip_address_db_record()`` queries the API first and falls back to the</span>
|
||||
<span class="c1"># bundled/cached MMDB on any non-2xx response or network error. A 401/403</span>
|
||||
<span class="c1"># propagates as ``InvalidIPinfoAPIKey`` so the CLI exits fatally.</span>
|
||||
<span class="c1">#</span>
|
||||
<span class="c1"># The IPinfo Lite API is documented as having no daily or monthly request</span>
|
||||
<span class="c1"># limit ("unlimited access"), so there is no rate-limit or quota handling</span>
|
||||
<span class="c1"># here — adding it would be inventing behavior the service doesn't document.</span>
|
||||
<span class="c1"># Authentication uses the documented ``?token=`` query parameter.</span>
|
||||
<span class="n">_IPINFO_API_URL</span> <span class="o">=</span> <span class="s2">"https://api.ipinfo.io/lite"</span>
|
||||
<span class="c1"># Account-info / quota endpoint. Separate from the lookup URL because ``/me``</span>
|
||||
<span class="c1"># lives at the ipinfo.io root, not under ``/lite``. Hitting it at startup</span>
|
||||
<span class="c1"># both validates the token and surfaces plan/usage details; IPinfo documents</span>
|
||||
<span class="c1"># it as a quota-free meta endpoint.</span>
|
||||
<span class="n">_IPINFO_ACCOUNT_URL</span> <span class="o">=</span> <span class="s2">"https://ipinfo.io/me"</span>
|
||||
<span class="n">_IPINFO_API_TOKEN</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="n">_IPINFO_API_TIMEOUT</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="mf">5.0</span>
|
||||
<span class="c1"># Default cooldowns when the API returns 429/402 without a ``Retry-After``</span>
|
||||
<span class="c1"># header. Rate limits are usually short; quota resets (402) are typically at a</span>
|
||||
<span class="c1"># day/month boundary, so we pick a longer default there.</span>
|
||||
<span class="n">_IPINFO_API_RATE_LIMIT_COOLDOWN_SECONDS</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="mf">300.0</span>
|
||||
<span class="n">_IPINFO_API_QUOTA_COOLDOWN_SECONDS</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="mf">3600.0</span>
|
||||
<span class="c1"># Unix timestamp before which lookups skip the API and go straight to the</span>
|
||||
<span class="c1"># MMDB. ``0`` means the API is currently available.</span>
|
||||
<span class="n">_IPINFO_API_COOLDOWN_UNTIL</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="mf">0.0</span>
|
||||
<span class="c1"># Latch for recovery logging: True while the API is in a rate-limited or</span>
|
||||
<span class="c1"># quota-exhausted state, so the next successful lookup can log "recovered"</span>
|
||||
<span class="c1"># exactly once per event.</span>
|
||||
<span class="n">_IPINFO_API_RATE_LIMITED</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
|
||||
|
||||
|
||||
<div class="viewcode-block" id="configure_ipinfo_api">
|
||||
@@ -636,171 +622,51 @@
|
||||
<span class="w"> </span><span class="sd">"""Configure the IPinfo Lite REST API as the primary source for IP lookups.</span>
|
||||
|
||||
<span class="sd"> When a token is configured, ``get_ip_address_db_record()`` hits the API</span>
|
||||
<span class="sd"> first for every lookup and falls back to the MMDB on rate-limit, quota, or</span>
|
||||
<span class="sd"> network errors. An invalid token raises ``InvalidIPinfoAPIKey`` — the CLI</span>
|
||||
<span class="sd"> catches that and exits fatally.</span>
|
||||
<span class="sd"> first for every lookup and falls back to the MMDB on network errors. An</span>
|
||||
<span class="sd"> invalid token raises ``InvalidIPinfoAPIKey`` — the CLI catches that and</span>
|
||||
<span class="sd"> exits fatally.</span>
|
||||
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> token: IPinfo API token. ``None`` or empty disables the API.</span>
|
||||
<span class="sd"> probe: If ``True``, verify the token by hitting ``/me`` (and, if that</span>
|
||||
<span class="sd"> is unreachable, by looking up ``1.1.1.1``). A 401/403 raises</span>
|
||||
<span class="sd"> ``InvalidIPinfoAPIKey``; other errors are logged and the token is</span>
|
||||
<span class="sd"> still accepted so per-request fallback can take over.</span>
|
||||
<span class="sd"> probe: If ``True``, verify the token by looking up ``1.1.1.1``. A</span>
|
||||
<span class="sd"> 401/403 raises ``InvalidIPinfoAPIKey``; other errors are logged</span>
|
||||
<span class="sd"> and the token is still accepted so per-request fallback can take</span>
|
||||
<span class="sd"> over.</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">global</span> <span class="n">_IPINFO_API_TOKEN</span>
|
||||
<span class="k">global</span> <span class="n">_IPINFO_API_COOLDOWN_UNTIL</span><span class="p">,</span> <span class="n">_IPINFO_API_RATE_LIMITED</span>
|
||||
|
||||
<span class="n">_IPINFO_API_TOKEN</span> <span class="o">=</span> <span class="n">token</span> <span class="ow">or</span> <span class="kc">None</span>
|
||||
<span class="n">_IPINFO_API_COOLDOWN_UNTIL</span> <span class="o">=</span> <span class="mf">0.0</span>
|
||||
<span class="n">_IPINFO_API_RATE_LIMITED</span> <span class="o">=</span> <span class="kc">False</span>
|
||||
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">_IPINFO_API_TOKEN</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">_IPINFO_API_TOKEN</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">probe</span><span class="p">:</span>
|
||||
<span class="k">return</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">probe</span><span class="p">:</span>
|
||||
<span class="c1"># Verify the token. Any network/quota failure here is non-fatal — we</span>
|
||||
<span class="c1"># still accept the token and let per-request fallback handle it — but</span>
|
||||
<span class="c1"># an invalid-key response must fail fast so operators notice</span>
|
||||
<span class="c1"># immediately instead of seeing silent MMDB-only lookups all day.</span>
|
||||
<span class="c1">#</span>
|
||||
<span class="c1"># The /me meta endpoint doubles as a free-of-quota token check and a</span>
|
||||
<span class="c1"># plan/usage lookup, so we try it first. If /me is unreachable, fall</span>
|
||||
<span class="c1"># back to a lookup of 1.1.1.1 to validate the token.</span>
|
||||
<span class="n">account</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">dict</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">account</span> <span class="o">=</span> <span class="n">_ipinfo_api_account_info</span><span class="p">()</span>
|
||||
<span class="k">except</span> <span class="n">InvalidIPinfoAPIKey</span><span class="p">:</span>
|
||||
<span class="k">raise</span>
|
||||
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">"IPinfo account info fetch failed: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">account</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">summary</span> <span class="o">=</span> <span class="n">_format_ipinfo_account_summary</span><span class="p">(</span><span class="n">account</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">summary</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s2">"IPinfo API configured — </span><span class="si">{</span><span class="n">summary</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">"IPinfo API configured"</span><span class="p">)</span>
|
||||
<span class="k">return</span>
|
||||
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">_ipinfo_api_lookup</span><span class="p">(</span><span class="s2">"1.1.1.1"</span><span class="p">)</span>
|
||||
<span class="k">except</span> <span class="n">InvalidIPinfoAPIKey</span><span class="p">:</span>
|
||||
<span class="k">raise</span>
|
||||
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="sa">f</span><span class="s2">"IPinfo API probe failed (will fall back per-request): </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">"IPinfo API configured"</span><span class="p">)</span></div>
|
||||
|
||||
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">_ipinfo_api_account_info</span><span class="p">()</span> <span class="o">-></span> <span class="n">Optional</span><span class="p">[</span><span class="nb">dict</span><span class="p">]:</span>
|
||||
<span class="w"> </span><span class="sd">"""Fetch the IPinfo ``/me`` account endpoint.</span>
|
||||
|
||||
<span class="sd"> Returns the parsed JSON dict on success, or ``None`` when the endpoint is</span>
|
||||
<span class="sd"> unreachable (network error, non-JSON body, non-2xx other than 401/403).</span>
|
||||
<span class="sd"> A 401/403 raises ``InvalidIPinfoAPIKey`` — this endpoint is the best way</span>
|
||||
<span class="sd"> to validate a token since it doesn't consume a lookup-quota unit.</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">_IPINFO_API_TOKEN</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="kc">None</span>
|
||||
<span class="n">headers</span> <span class="o">=</span> <span class="p">{</span>
|
||||
<span class="s2">"User-Agent"</span><span class="p">:</span> <span class="n">USER_AGENT</span><span class="p">,</span>
|
||||
<span class="s2">"Authorization"</span><span class="p">:</span> <span class="sa">f</span><span class="s2">"Bearer </span><span class="si">{</span><span class="n">_IPINFO_API_TOKEN</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span>
|
||||
<span class="s2">"Accept"</span><span class="p">:</span> <span class="s2">"application/json"</span><span class="p">,</span>
|
||||
<span class="p">}</span>
|
||||
<span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span>
|
||||
<span class="n">_IPINFO_ACCOUNT_URL</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="n">_IPINFO_API_TIMEOUT</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">status_code</span> <span class="ow">in</span> <span class="p">(</span><span class="mi">401</span><span class="p">,</span> <span class="mi">403</span><span class="p">):</span>
|
||||
<span class="k">raise</span> <span class="n">InvalidIPinfoAPIKey</span><span class="p">(</span>
|
||||
<span class="sa">f</span><span class="s2">"IPinfo API rejected the configured token (HTTP </span><span class="si">{</span><span class="n">response</span><span class="o">.</span><span class="n">status_code</span><span class="si">}</span><span class="s2">)"</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">response</span><span class="o">.</span><span class="n">ok</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">"IPinfo /me returned HTTP </span><span class="si">{</span><span class="n">response</span><span class="o">.</span><span class="n">status_code</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="kc">None</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">payload</span> <span class="o">=</span> <span class="n">response</span><span class="o">.</span><span class="n">json</span><span class="p">()</span>
|
||||
<span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="kc">None</span>
|
||||
<span class="k">return</span> <span class="n">payload</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="nb">dict</span><span class="p">)</span> <span class="k">else</span> <span class="kc">None</span>
|
||||
<span class="n">_ipinfo_api_lookup</span><span class="p">(</span><span class="s2">"1.1.1.1"</span><span class="p">)</span>
|
||||
<span class="k">except</span> <span class="n">InvalidIPinfoAPIKey</span><span class="p">:</span>
|
||||
<span class="k">raise</span>
|
||||
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="sa">f</span><span class="s2">"IPinfo API probe failed (will fall back per-request): </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">"IPinfo API configured"</span><span class="p">)</span></div>
|
||||
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">_format_ipinfo_account_summary</span><span class="p">(</span><span class="n">account</span><span class="p">:</span> <span class="nb">dict</span><span class="p">)</span> <span class="o">-></span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
|
||||
<span class="w"> </span><span class="sd">"""Render a short, log-friendly summary of the IPinfo /me response.</span>
|
||||
|
||||
<span class="sd"> Field names in /me have varied across IPinfo plan generations, so we</span>
|
||||
<span class="sd"> probe a few aliases rather than commit to one schema. If nothing</span>
|
||||
<span class="sd"> useful is present we return ``None`` and the caller falls back to a</span>
|
||||
<span class="sd"> generic "configured" message.</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">plan</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="n">account</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"plan"</span><span class="p">)</span>
|
||||
<span class="ow">or</span> <span class="n">account</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"tier"</span><span class="p">)</span>
|
||||
<span class="ow">or</span> <span class="n">account</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"token_type"</span><span class="p">)</span>
|
||||
<span class="ow">or</span> <span class="n">account</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"type"</span><span class="p">)</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">limit</span> <span class="o">=</span> <span class="n">account</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"limit"</span><span class="p">)</span> <span class="ow">or</span> <span class="n">account</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"monthly_limit"</span><span class="p">)</span>
|
||||
<span class="n">remaining</span> <span class="o">=</span> <span class="n">account</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"remaining"</span><span class="p">)</span> <span class="ow">or</span> <span class="n">account</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"requests_remaining"</span><span class="p">)</span>
|
||||
<span class="n">used</span> <span class="o">=</span> <span class="n">account</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"month"</span><span class="p">)</span> <span class="ow">or</span> <span class="n">account</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"month_requests"</span><span class="p">)</span> <span class="ow">or</span> <span class="n">account</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"used"</span><span class="p">)</span>
|
||||
|
||||
<span class="n">parts</span> <span class="o">=</span> <span class="p">[]</span>
|
||||
<span class="k">if</span> <span class="n">plan</span><span class="p">:</span>
|
||||
<span class="n">parts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">"plan: </span><span class="si">{</span><span class="n">plan</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">used</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">limit</span><span class="p">:</span>
|
||||
<span class="n">parts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">"usage: </span><span class="si">{</span><span class="n">used</span><span class="si">}</span><span class="s2">/</span><span class="si">{</span><span class="n">limit</span><span class="si">}</span><span class="s2"> this month"</span><span class="p">)</span>
|
||||
<span class="k">elif</span> <span class="n">limit</span><span class="p">:</span>
|
||||
<span class="n">parts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">"monthly limit: </span><span class="si">{</span><span class="n">limit</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">remaining</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">parts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">remaining</span><span class="si">}</span><span class="s2"> remaining"</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="s2">", "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">parts</span><span class="p">)</span> <span class="k">if</span> <span class="n">parts</span> <span class="k">else</span> <span class="kc">None</span>
|
||||
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">_parse_retry_after</span><span class="p">(</span><span class="n">response</span><span class="p">,</span> <span class="n">default_seconds</span><span class="p">:</span> <span class="nb">float</span><span class="p">)</span> <span class="o">-></span> <span class="nb">float</span><span class="p">:</span>
|
||||
<span class="w"> </span><span class="sd">"""Parse an HTTP ``Retry-After`` header as seconds.</span>
|
||||
|
||||
<span class="sd"> Supports the delta-seconds form. HTTP-date form is rare enough for an API</span>
|
||||
<span class="sd"> client to ignore; we just fall back to the default.</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">raw</span> <span class="o">=</span> <span class="n">response</span><span class="o">.</span><span class="n">headers</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"Retry-After"</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">raw</span><span class="p">:</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="nb">max</span><span class="p">(</span><span class="nb">float</span><span class="p">(</span><span class="n">raw</span><span class="o">.</span><span class="n">strip</span><span class="p">()),</span> <span class="mf">1.0</span><span class="p">)</span>
|
||||
<span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
|
||||
<span class="k">pass</span>
|
||||
<span class="k">return</span> <span class="n">default_seconds</span>
|
||||
|
||||
|
||||
<span class="k">def</span><span class="w"> </span><span class="nf">_ipinfo_api_lookup</span><span class="p">(</span><span class="n">ip_address</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="n">Optional</span><span class="p">[</span><span class="n">_IPDatabaseRecord</span><span class="p">]:</span>
|
||||
<span class="w"> </span><span class="sd">"""Look up an IP via the IPinfo Lite REST API.</span>
|
||||
|
||||
<span class="sd"> Returns the normalized record on success, or ``None`` when the API is</span>
|
||||
<span class="sd"> unavailable for any reason the caller should fall back from (network</span>
|
||||
<span class="sd"> error, 429 rate limit, 402 quota exhausted, malformed response).</span>
|
||||
|
||||
<span class="sd"> On 429/402 the API is put in a cooldown (using ``Retry-After`` when</span>
|
||||
<span class="sd"> present) so we stop hammering it, and we log once per event at warning</span>
|
||||
<span class="sd"> level. After the cooldown expires the next lookup retries transparently;</span>
|
||||
<span class="sd"> a successful retry logs "API recovered" once at info level so operators</span>
|
||||
<span class="sd"> can see service came back.</span>
|
||||
|
||||
<span class="sd"> Raises:</span>
|
||||
<span class="sd"> InvalidIPinfoAPIKey: on 401/403. Propagates to abort the run.</span>
|
||||
<span class="sd"> Returns the normalized record on success, or ``None`` on network error or</span>
|
||||
<span class="sd"> any non-2xx response (other than 401/403). 401/403 raises</span>
|
||||
<span class="sd"> ``InvalidIPinfoAPIKey``.</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="k">global</span> <span class="n">_IPINFO_API_COOLDOWN_UNTIL</span><span class="p">,</span> <span class="n">_IPINFO_API_RATE_LIMITED</span>
|
||||
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">_IPINFO_API_TOKEN</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="kc">None</span>
|
||||
<span class="k">if</span> <span class="n">_IPINFO_API_COOLDOWN_UNTIL</span> <span class="ow">and</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o"><</span> <span class="n">_IPINFO_API_COOLDOWN_UNTIL</span><span class="p">:</span>
|
||||
<span class="k">return</span> <span class="kc">None</span>
|
||||
|
||||
<span class="n">url</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">_IPINFO_API_URL</span><span class="si">}</span><span class="s2">/</span><span class="si">{</span><span class="n">ip_address</span><span class="si">}</span><span class="s2">"</span>
|
||||
<span class="n">headers</span> <span class="o">=</span> <span class="p">{</span>
|
||||
<span class="s2">"User-Agent"</span><span class="p">:</span> <span class="n">USER_AGENT</span><span class="p">,</span>
|
||||
<span class="s2">"Authorization"</span><span class="p">:</span> <span class="sa">f</span><span class="s2">"Bearer </span><span class="si">{</span><span class="n">_IPINFO_API_TOKEN</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span>
|
||||
<span class="s2">"Accept"</span><span class="p">:</span> <span class="s2">"application/json"</span><span class="p">,</span>
|
||||
<span class="p">}</span>
|
||||
<span class="n">params</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"token"</span><span class="p">:</span> <span class="n">_IPINFO_API_TOKEN</span><span class="p">}</span>
|
||||
<span class="n">headers</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"User-Agent"</span><span class="p">:</span> <span class="n">USER_AGENT</span><span class="p">,</span> <span class="s2">"Accept"</span><span class="p">:</span> <span class="s2">"application/json"</span><span class="p">}</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="n">_IPINFO_API_TIMEOUT</span><span class="p">)</span>
|
||||
<span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span>
|
||||
<span class="n">url</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">,</span> <span class="n">params</span><span class="o">=</span><span class="n">params</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="n">_IPINFO_API_TIMEOUT</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">except</span> <span class="n">requests</span><span class="o">.</span><span class="n">exceptions</span><span class="o">.</span><span class="n">RequestException</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">"IPinfo API request for </span><span class="si">{</span><span class="n">ip_address</span><span class="si">}</span><span class="s2"> failed: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="kc">None</span>
|
||||
@@ -809,35 +675,6 @@
|
||||
<span class="k">raise</span> <span class="n">InvalidIPinfoAPIKey</span><span class="p">(</span>
|
||||
<span class="sa">f</span><span class="s2">"IPinfo API rejected the configured token (HTTP </span><span class="si">{</span><span class="n">response</span><span class="o">.</span><span class="n">status_code</span><span class="si">}</span><span class="s2">)"</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">429</span><span class="p">:</span>
|
||||
<span class="n">cooldown</span> <span class="o">=</span> <span class="n">_parse_retry_after</span><span class="p">(</span><span class="n">response</span><span class="p">,</span> <span class="n">_IPINFO_API_RATE_LIMIT_COOLDOWN_SECONDS</span><span class="p">)</span>
|
||||
<span class="n">_IPINFO_API_COOLDOWN_UNTIL</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">+</span> <span class="n">cooldown</span>
|
||||
<span class="c1"># First hit of a rate-limit event is visible at warning; subsequent</span>
|
||||
<span class="c1"># 429s after cooldown-and-retry cycles stay at debug so we don't spam</span>
|
||||
<span class="c1"># the log when a run spans a long quota reset.</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">_IPINFO_API_RATE_LIMITED</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span>
|
||||
<span class="s2">"IPinfo API rate limit hit; falling back to the local MMDB "</span>
|
||||
<span class="sa">f</span><span class="s2">"for </span><span class="si">{</span><span class="n">cooldown</span><span class="si">:</span><span class="s2">.0f</span><span class="si">}</span><span class="s2">s before retrying"</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">_IPINFO_API_RATE_LIMITED</span> <span class="o">=</span> <span class="kc">True</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">"IPinfo API still rate-limited; retry after </span><span class="si">{</span><span class="n">cooldown</span><span class="si">:</span><span class="s2">.0f</span><span class="si">}</span><span class="s2">s"</span><span class="p">)</span>
|
||||
<span class="k">return</span> <span class="kc">None</span>
|
||||
<span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">402</span><span class="p">:</span>
|
||||
<span class="n">cooldown</span> <span class="o">=</span> <span class="n">_parse_retry_after</span><span class="p">(</span><span class="n">response</span><span class="p">,</span> <span class="n">_IPINFO_API_QUOTA_COOLDOWN_SECONDS</span><span class="p">)</span>
|
||||
<span class="n">_IPINFO_API_COOLDOWN_UNTIL</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">+</span> <span class="n">cooldown</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">_IPINFO_API_RATE_LIMITED</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span>
|
||||
<span class="s2">"IPinfo API quota exhausted; falling back to the local MMDB "</span>
|
||||
<span class="sa">f</span><span class="s2">"for </span><span class="si">{</span><span class="n">cooldown</span><span class="si">:</span><span class="s2">.0f</span><span class="si">}</span><span class="s2">s before retrying"</span>
|
||||
<span class="p">)</span>
|
||||
<span class="n">_IPINFO_API_RATE_LIMITED</span> <span class="o">=</span> <span class="kc">True</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
|
||||
<span class="sa">f</span><span class="s2">"IPinfo API quota still exhausted; retry after </span><span class="si">{</span><span class="n">cooldown</span><span class="si">:</span><span class="s2">.0f</span><span class="si">}</span><span class="s2">s"</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">return</span> <span class="kc">None</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">response</span><span class="o">.</span><span class="n">ok</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
|
||||
<span class="sa">f</span><span class="s2">"IPinfo API returned HTTP </span><span class="si">{</span><span class="n">response</span><span class="o">.</span><span class="n">status_code</span><span class="si">}</span><span class="s2"> for </span><span class="si">{</span><span class="n">ip_address</span><span class="si">}</span><span class="s2">"</span>
|
||||
@@ -852,11 +689,6 @@
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="kc">None</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">_IPINFO_API_RATE_LIMITED</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">"IPinfo API recovered; resuming API lookups"</span><span class="p">)</span>
|
||||
<span class="n">_IPINFO_API_RATE_LIMITED</span> <span class="o">=</span> <span class="kc">False</span>
|
||||
<span class="n">_IPINFO_API_COOLDOWN_UNTIL</span> <span class="o">=</span> <span class="mf">0.0</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">_normalize_ip_record</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
|
||||
|
||||
|
||||
@@ -1264,7 +1096,22 @@
|
||||
<span class="c1"># classification. Better than leaving the row unattributed.</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"name"</span><span class="p">]</span> <span class="o">=</span> <span class="n">info</span><span class="p">[</span><span class="s2">"as_name"</span><span class="p">]</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">cache</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="c1"># Don't cache weak-fallback attributions — rows where we had no PTR AND</span>
|
||||
<span class="c1"># the ASN domain wasn't in the map, so ``name`` is just the raw ``as_name``</span>
|
||||
<span class="c1"># from the MMDB. ``get_reverse_dns()`` swallows every ``DNSException`` as</span>
|
||||
<span class="c1"># ``None``, so a transient PTR lookup failure (timeout, SERVFAIL, OSError)</span>
|
||||
<span class="c1"># is indistinguishable from a real no-PTR case at this point. Caching the</span>
|
||||
<span class="c1"># weak result would poison the 4-hour cache with a misattribution even</span>
|
||||
<span class="c1"># after the PTR becomes resolvable again. Re-running on the next lookup</span>
|
||||
<span class="c1"># is cheap and either produces a proper PTR-backed match or the same</span>
|
||||
<span class="c1"># (still-best-effort) ASN attribution.</span>
|
||||
<span class="n">weak_fallback</span> <span class="o">=</span> <span class="p">(</span>
|
||||
<span class="n">info</span><span class="p">[</span><span class="s2">"reverse_dns"</span><span class="p">]</span> <span class="ow">is</span> <span class="kc">None</span>
|
||||
<span class="ow">and</span> <span class="n">info</span><span class="p">[</span><span class="s2">"type"</span><span class="p">]</span> <span class="ow">is</span> <span class="kc">None</span>
|
||||
<span class="ow">and</span> <span class="n">info</span><span class="p">[</span><span class="s2">"name"</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span>
|
||||
<span class="ow">and</span> <span class="n">info</span><span class="p">[</span><span class="s2">"name"</span><span class="p">]</span> <span class="o">==</span> <span class="n">info</span><span class="p">[</span><span class="s2">"as_name"</span><span class="p">]</span>
|
||||
<span class="p">)</span>
|
||||
<span class="k">if</span> <span class="n">cache</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">weak_fallback</span><span class="p">:</span>
|
||||
<span class="n">cache</span><span class="p">[</span><span class="n">ip_address</span><span class="p">]</span> <span class="o">=</span> <span class="n">info</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="sa">f</span><span class="s2">"IP address </span><span class="si">{</span><span class="n">ip_address</span><span class="si">}</span><span class="s2"> added to cache"</span><span class="p">)</span>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const DOCUMENTATION_OPTIONS = {
|
||||
VERSION: '9.10.0',
|
||||
VERSION: '9.10.2',
|
||||
LANGUAGE: 'en',
|
||||
COLLAPSE_INDEX: false,
|
||||
BUILDER: 'html',
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>API reference — parsedmarc 9.10.0 documentation</title>
|
||||
<title>API reference — parsedmarc 9.10.2 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=e59714d7" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=3c16008f"></script>
|
||||
<script src="_static/documentation_options.js?v=af960efc"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
@@ -1205,17 +1205,17 @@ to save in Splunk</p>
|
||||
<span class="sig-prename descclassname"><span class="pre">parsedmarc.utils.</span></span><span class="sig-name descname"><span class="pre">configure_ipinfo_api</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">token</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">str</span><span class="w"> </span><span class="p"><span class="pre">|</span></span><span class="w"> </span><span class="pre">None</span></span></em>, <em class="sig-param"><span class="keyword-only-separator o"><abbr title="Keyword-only parameters separator (PEP 3102)"><span class="pre">*</span></abbr></span></em>, <em class="sig-param"><span class="n"><span class="pre">probe</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">bool</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">True</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">→</span> <span class="sig-return-typehint"><span class="pre">None</span></span></span><a class="reference internal" href="_modules/parsedmarc/utils.html#configure_ipinfo_api"><span class="viewcode-link"><span class="pre">[source]</span></span></a><a class="headerlink" href="#parsedmarc.utils.configure_ipinfo_api" title="Link to this definition"></a></dt>
|
||||
<dd><p>Configure the IPinfo Lite REST API as the primary source for IP lookups.</p>
|
||||
<p>When a token is configured, <code class="docutils literal notranslate"><span class="pre">get_ip_address_db_record()</span></code> hits the API
|
||||
first for every lookup and falls back to the MMDB on rate-limit, quota, or
|
||||
network errors. An invalid token raises <code class="docutils literal notranslate"><span class="pre">InvalidIPinfoAPIKey</span></code> — the CLI
|
||||
catches that and exits fatally.</p>
|
||||
first for every lookup and falls back to the MMDB on network errors. An
|
||||
invalid token raises <code class="docutils literal notranslate"><span class="pre">InvalidIPinfoAPIKey</span></code> — the CLI catches that and
|
||||
exits fatally.</p>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
|
||||
<dd class="field-odd"><ul class="simple">
|
||||
<li><p><strong>token</strong> – IPinfo API token. <code class="docutils literal notranslate"><span class="pre">None</span></code> or empty disables the API.</p></li>
|
||||
<li><p><strong>probe</strong> – If <code class="docutils literal notranslate"><span class="pre">True</span></code>, verify the token by hitting <code class="docutils literal notranslate"><span class="pre">/me</span></code> (and, if that
|
||||
is unreachable, by looking up <code class="docutils literal notranslate"><span class="pre">1.1.1.1</span></code>). A 401/403 raises
|
||||
<code class="docutils literal notranslate"><span class="pre">InvalidIPinfoAPIKey</span></code>; other errors are logged and the token is
|
||||
still accepted so per-request fallback can take over.</p></li>
|
||||
<li><p><strong>probe</strong> – If <code class="docutils literal notranslate"><span class="pre">True</span></code>, verify the token by looking up <code class="docutils literal notranslate"><span class="pre">1.1.1.1</span></code>. A
|
||||
401/403 raises <code class="docutils literal notranslate"><span class="pre">InvalidIPinfoAPIKey</span></code>; other errors are logged
|
||||
and the token is still accepted so per-request fallback can take
|
||||
over.</p></li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
+2
-2
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Contributing to parsedmarc — parsedmarc 9.10.0 documentation</title>
|
||||
<title>Contributing to parsedmarc — parsedmarc 9.10.2 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=e59714d7" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=3c16008f"></script>
|
||||
<script src="_static/documentation_options.js?v=af960efc"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
|
||||
+2
-2
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Accessing an inbox using OWA/EWS — parsedmarc 9.10.0 documentation</title>
|
||||
<title>Accessing an inbox using OWA/EWS — parsedmarc 9.10.2 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=e59714d7" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=3c16008f"></script>
|
||||
<script src="_static/documentation_options.js?v=af960efc"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
|
||||
+2
-2
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Understanding DMARC — parsedmarc 9.10.0 documentation</title>
|
||||
<title>Understanding DMARC — parsedmarc 9.10.2 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=e59714d7" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=3c16008f"></script>
|
||||
<script src="_static/documentation_options.js?v=af960efc"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
|
||||
+2
-2
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Elasticsearch and Kibana — parsedmarc 9.10.0 documentation</title>
|
||||
<title>Elasticsearch and Kibana — parsedmarc 9.10.2 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=e59714d7" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=3c16008f"></script>
|
||||
<script src="_static/documentation_options.js?v=af960efc"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
|
||||
+2
-2
@@ -5,14 +5,14 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Index — parsedmarc 9.10.0 documentation</title>
|
||||
<title>Index — parsedmarc 9.10.2 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=e59714d7" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=3c16008f"></script>
|
||||
<script src="_static/documentation_options.js?v=af960efc"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
|
||||
+2
-2
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>parsedmarc documentation - Open source DMARC report analyzer and visualizer — parsedmarc 9.10.0 documentation</title>
|
||||
<title>parsedmarc documentation - Open source DMARC report analyzer and visualizer — parsedmarc 9.10.2 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=e59714d7" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=3c16008f"></script>
|
||||
<script src="_static/documentation_options.js?v=af960efc"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
|
||||
+2
-2
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Installation — parsedmarc 9.10.0 documentation</title>
|
||||
<title>Installation — parsedmarc 9.10.2 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=e59714d7" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=3c16008f"></script>
|
||||
<script src="_static/documentation_options.js?v=af960efc"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
|
||||
+2
-2
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Using the Kibana dashboards — parsedmarc 9.10.0 documentation</title>
|
||||
<title>Using the Kibana dashboards — parsedmarc 9.10.2 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=e59714d7" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=3c16008f"></script>
|
||||
<script src="_static/documentation_options.js?v=af960efc"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
|
||||
+2
-2
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>What about mailing lists? — parsedmarc 9.10.0 documentation</title>
|
||||
<title>What about mailing lists? — parsedmarc 9.10.2 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=e59714d7" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=3c16008f"></script>
|
||||
<script src="_static/documentation_options.js?v=af960efc"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
|
||||
BIN
Binary file not shown.
+2
-2
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>OpenSearch and Grafana — parsedmarc 9.10.0 documentation</title>
|
||||
<title>OpenSearch and Grafana — parsedmarc 9.10.2 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=e59714d7" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=3c16008f"></script>
|
||||
<script src="_static/documentation_options.js?v=af960efc"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
|
||||
+2
-2
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Sample outputs — parsedmarc 9.10.0 documentation</title>
|
||||
<title>Sample outputs — parsedmarc 9.10.2 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=e59714d7" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=3c16008f"></script>
|
||||
<script src="_static/documentation_options.js?v=af960efc"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
|
||||
+2
-2
@@ -5,14 +5,14 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Python Module Index — parsedmarc 9.10.0 documentation</title>
|
||||
<title>Python Module Index — parsedmarc 9.10.2 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=e59714d7" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=3c16008f"></script>
|
||||
<script src="_static/documentation_options.js?v=af960efc"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Search — parsedmarc 9.10.0 documentation</title>
|
||||
<title>Search — parsedmarc 9.10.2 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=e59714d7" />
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=3c16008f"></script>
|
||||
<script src="_static/documentation_options.js?v=af960efc"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+2
-2
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Splunk — parsedmarc 9.10.0 documentation</title>
|
||||
<title>Splunk — parsedmarc 9.10.2 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=e59714d7" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=3c16008f"></script>
|
||||
<script src="_static/documentation_options.js?v=af960efc"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
|
||||
+2
-2
@@ -6,14 +6,14 @@
|
||||
<meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Using parsedmarc — parsedmarc 9.10.0 documentation</title>
|
||||
<title>Using parsedmarc — parsedmarc 9.10.2 documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=b86133f3" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/css/theme.css?v=e59714d7" />
|
||||
|
||||
|
||||
<script src="_static/jquery.js?v=5d32c60e"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
|
||||
<script src="_static/documentation_options.js?v=3c16008f"></script>
|
||||
<script src="_static/documentation_options.js?v=af960efc"></script>
|
||||
<script src="_static/doctools.js?v=9bcbadda"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
|
||||
<script src="_static/js/theme.js"></script>
|
||||
|
||||
Reference in New Issue
Block a user