<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Opt-In Software Blog</title>
  <icon>https://optinsoft.net/blog/icon.png</icon>
  
  <link href="https://optinsoft.net/blog/atom.xml" rel="self"/>
  
  <link href="https://optinsoft.net/blog/"/>
  <updated>2026-06-30T10:56:34.587Z</updated>
  <id>https://optinsoft.net/blog/</id>
  
  <author>
    <name>Opt-In Software</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>Understanding SslMode and UpstreamSslMode in ProxyMapService</title>
    <link href="https://optinsoft.net/blog/2026/06/30/Understanding-SslMode-and-UpstreamSslMode-in-ProxyMapService/"/>
    <id>https://optinsoft.net/blog/2026/06/30/Understanding-SslMode-and-UpstreamSslMode-in-ProxyMapService/</id>
    <published>2026-06-30T10:54:07.000Z</published>
    <updated>2026-06-30T10:56:34.587Z</updated>
    
    <content type="html"><![CDATA[<p>In the previous article, <em><a href="/blog/2026/06/11/SSL-TLS-Traffic-Decryption-in-ProxyMapService/">SSL&#x2F;TLS Traffic Decryption in ProxyMapService</a></em>, we looked at how ProxyMapService can decrypt SSL&#x2F;TLS traffic by acting as a man-in-the-middle (MITM) proxy.</p><p>However, before traffic can be decrypted, ProxyMapService must first determine an important detail:</p><ul><li>Is the client using TLS?</li><li>Does the upstream server expect TLS?</li></ul><p>In many environments the answers are obvious, but not always. ProxyMapService provides two configuration options that allow you to control this behavior explicitly:</p><ul><li><code>SslMode</code></li><li><code>UpstreamSslMode</code></li></ul><p>Both settings support the same three values:</p><pre><code class="hljs json"><span class="hljs-string">&quot;No&quot;</span><span class="hljs-string">&quot;Yes&quot;</span><span class="hljs-string">&quot;Auto&quot;</span></code></pre><p>The default value for both settings is:</p><pre><code class="hljs json"><span class="hljs-string">&quot;Auto&quot;</span></code></pre><h2 id="Where-These-Settings-Can-Be-Configured"><a href="#Where-These-Settings-Can-Be-Configured" class="headerlink" title="Where These Settings Can Be Configured"></a>Where These Settings Can Be Configured</h2><p>Like <code>DecryptSSL</code>, both settings can be configured either for a listener or for an individual host rule.</p><h3 id="Listener-Configuration"><a href="#Listener-Configuration" class="headerlink" title="Listener Configuration"></a>Listener Configuration</h3><pre><code class="hljs json"><span class="hljs-attr">&quot;Listen&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span>    <span class="hljs-attr">&quot;Port&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">5000</span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;RejectHttpProxy&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;DecryptSSL&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;SslMode&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Yes&quot;</span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;UpstreamSslMode&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;No&quot;</span><span class="hljs-punctuation">&#125;</span></code></pre><p>When configured on a listener, the settings apply to every connection received on that listening port (or port range).</p><p>This is useful when all traffic arriving on a particular port follows the same protocol.</p><h2 id="Host-Rule-Configuration"><a href="#Host-Rule-Configuration" class="headerlink" title="Host Rule Configuration"></a>Host Rule Configuration</h2><p>The same settings can be configured for individual destinations.</p><p>Example:</p><pre><code class="hljs json"><span class="hljs-attr">&quot;HostRules&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span>    <span class="hljs-attr">&quot;Items&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>        <span class="hljs-punctuation">&#123;</span>            <span class="hljs-attr">&quot;Pattern&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;^mysite\\.com$&quot;</span><span class="hljs-punctuation">,</span>            <span class="hljs-attr">&quot;HostPort&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">443</span><span class="hljs-punctuation">,</span>            <span class="hljs-attr">&quot;DecryptSSL&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span><span class="hljs-punctuation">,</span>            <span class="hljs-attr">&quot;SslMode&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Yes&quot;</span><span class="hljs-punctuation">,</span>            <span class="hljs-attr">&quot;UpstreamSslMode&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;No&quot;</span>        <span class="hljs-punctuation">&#125;</span>    <span class="hljs-punctuation">]</span><span class="hljs-punctuation">&#125;</span></code></pre><p>This rule applies only to connections matching both:</p><ul><li><code>mysite.com</code></li><li>port <code>443</code></li></ul><p>Connections to the same host on other ports are unaffected.</p><p>Instead of using a regular expression, you can specify a host name directly:</p><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span>    <span class="hljs-attr">&quot;HostName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;mysite.com&quot;</span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;DecryptSSL&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;SslMode&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Yes&quot;</span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;UpstreamSslMode&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;No&quot;</span><span class="hljs-punctuation">&#125;</span></code></pre><p>Since no port is specified, the rule applies to every port for that host.</p><p>Host rules override listener settings whenever a connection matches the rule, allowing different SSL behavior for different destinations.</p><h2 id="Understanding-SslMode"><a href="#Understanding-SslMode" class="headerlink" title="Understanding SslMode"></a>Understanding SslMode</h2><p><code>SslMode</code> controls whether the incoming client connection is expected to use SSL&#x2F;TLS.</p><p>The available values are:</p><h3 id="No"><a href="#No" class="headerlink" title="No"></a>No</h3><p>The incoming connection is treated as plain TCP.</p><p>No TLS handshake is expected.</p><h3 id="Yes"><a href="#Yes" class="headerlink" title="Yes"></a>Yes</h3><p>The incoming connection is always treated as TLS.</p><p>ProxyMapService immediately begins TLS negotiation with the client.</p><h3 id="Auto"><a href="#Auto" class="headerlink" title="Auto"></a>Auto</h3><p>This is the default behavior.</p><p>Instead of relying on the listening port, ProxyMapService examines the first two bytes received from the client.</p><p>A TLS ClientHello always begins with:</p><pre><code class="hljs plaintext">0x16 0x03</code></pre><p>If this signature is detected, the connection is treated as TLS.</p><p>Otherwise, it is processed as an unencrypted connection.</p><p>This automatic detection allows HTTP and HTTPS traffic to coexist on the same listener without requiring separate ports.</p><h2 id="Understanding-UpstreamSslMode"><a href="#Understanding-UpstreamSslMode" class="headerlink" title="Understanding UpstreamSslMode"></a>Understanding UpstreamSslMode</h2><p><code>UpstreamSslMode</code> controls how ProxyMapService connects to the destination server.</p><p>Unlike <code>SslMode</code>, which examines the client connection, this setting determines whether the outbound connection should be encrypted.</p><p>The available values are the same:</p><h3 id="No-1"><a href="#No-1" class="headerlink" title="No"></a>No</h3><p>ProxyMapService always connects to the upstream server using plain TCP.</p><h3 id="Yes-1"><a href="#Yes-1" class="headerlink" title="Yes"></a>Yes</h3><p>ProxyMapService always establishes a TLS connection to the upstream server.</p><h3 id="Auto-1"><a href="#Auto-1" class="headerlink" title="Auto"></a>Auto</h3><p>This is the default behavior.</p><p>Instead of inspecting traffic, ProxyMapService determines whether TLS should be used based on the destination port.</p><p>The following ports are treated as secure by default:</p><ul><li>443 (HTTPS)</li><li>465 (SMTPS)</li><li>563 (NNTPS)</li><li>636 (LDAPS)</li><li>990 (FTPS)</li><li>992 (Telnet over TLS)</li><li>993 (IMAPS)</li><li>995 (POP3S)</li><li>3269 (Microsoft Global Catalog over SSL)</li><li>8443 (Alternative HTTPS)</li></ul><p>Connections to these ports are established using TLS.</p><p>Connections to other ports use plain TCP unless <code>UpstreamSslMode</code> is explicitly set to <code>Yes</code>.</p><h2 id="When-Should-You-Override-Auto"><a href="#When-Should-You-Override-Auto" class="headerlink" title="When Should You Override Auto?"></a>When Should You Override Auto?</h2><p>For most deployments, <code>Auto</code> is the recommended setting for both options.</p><p>However, explicit configuration is useful when working with non-standard environments.</p><p>Typical examples include:</p><ul><li>HTTPS services running on custom ports.</li><li>Plain HTTP services listening on port 443.</li><li>Legacy applications that tunnel TLS over unexpected ports.</li><li>Environments where protocol detection must be disabled for compatibility or performance reasons.</li></ul><p>In these situations, setting <code>SslMode</code> or <code>UpstreamSslMode</code> to <code>Yes</code> or <code>No</code> removes any ambiguity and ensures ProxyMapService uses the desired protocol.</p><h2 id="Conclusion"><a href="#Conclusion" class="headerlink" title="Conclusion"></a>Conclusion</h2><p><code>SslMode</code> and <code>UpstreamSslMode</code> give you precise control over how ProxyMapService handles encrypted connections.</p><p><code>SslMode</code> determines whether the client connection is encrypted, while <code>UpstreamSslMode</code> determines whether the connection to the destination server should use TLS.</p><p>In most cases, the default <code>Auto</code> mode works without any additional configuration by automatically detecting TLS on incoming connections and using well-known secure ports for outbound connections.</p><p>When working with non-standard network topologies or custom protocols, these settings allow ProxyMapService to communicate correctly with both clients and upstream servers without requiring changes to the application itself.</p>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;p&gt;In the previous article, &lt;em&gt;&lt;a href=&quot;/blog/2026/06/11/SSL-TLS-Traffic-Decryption-in-ProxyMapService/&quot;&gt;SSL&amp;#x2F;TLS Traffic Decryption</summary>
        
      
    
    
    
    <category term="ProxyMapService" scheme="https://optinsoft.net/blog/categories/ProxyMapService/"/>
    
    
    <category term="mitm" scheme="https://optinsoft.net/blog/tags/mitm/"/>
    
    <category term="ssl" scheme="https://optinsoft.net/blog/tags/ssl/"/>
    
    <category term="tls" scheme="https://optinsoft.net/blog/tags/tls/"/>
    
    <category term="decrypt" scheme="https://optinsoft.net/blog/tags/decrypt/"/>
    
    <category term="SslMode" scheme="https://optinsoft.net/blog/tags/SslMode/"/>
    
    <category term="UpstreamSslMode" scheme="https://optinsoft.net/blog/tags/UpstreamSslMode/"/>
    
  </entry>
  
  <entry>
    <title>Wattpad Text Selection and Copy Trick</title>
    <link href="https://optinsoft.net/blog/2026/06/18/Wattpad-Text-Selection-and-Copy-Trick/"/>
    <id>https://optinsoft.net/blog/2026/06/18/Wattpad-Text-Selection-and-Copy-Trick/</id>
    <published>2026-06-18T13:35:49.000Z</published>
    <updated>2026-06-18T13:38:28.434Z</updated>
    
    <content type="html"><![CDATA[<p>If you ever need to copy text from Wattpad on desktop, here’s a method that still works for me.</p><ol><li><p>Open the story&#x2F;chapter you want to copy from and wait until the page is fully loaded.</p></li><li><p>Open the browser’s Developer Tools:</p><ul><li>Chrome &#x2F; Edge: press <strong>F12</strong> or <strong>Ctrl + Shift + I</strong></li><li>Firefox: press <strong>F12</strong> or <strong>Ctrl + Shift + I</strong></li><li>Safari: enable the Develop menu first, then choose <strong>Develop → Show JavaScript Console</strong></li></ul></li><li><p>Go to the <strong>Console</strong> tab.</p></li><li><p>Paste and run this command:</p></li></ol><pre><code class="hljs javascript"><span class="hljs-variable language_">document</span>.<span class="hljs-property">onselectstart</span> = <span class="hljs-literal">null</span>;</code></pre><ol start="5"><li>After that, you should be able to select text on the page normally.</li><li>Highlight the text you want.</li><li>In the Console, run:</li></ol><pre><code class="hljs javascript"><span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-variable language_">window</span>.<span class="hljs-title function_">getSelection</span>().<span class="hljs-title function_">toString</span>())</code></pre><ol start="8"><li>The selected text will be printed in the console. You can then select it there and copy it to your clipboard with Ctrl+C.</li></ol><p>A couple of notes:</p><ul><li>Make sure the chapter has finished loading before you start.</li><li>If the selection doesn’t work immediately, refresh the page and try again.</li><li>This method was tested in a desktop browser using Developer Tools.</li></ul><p>Hope this helps someone.</p>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;p&gt;If you ever need to copy text from Wattpad on desktop, here’s a method that still works for me.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Open the</summary>
        
      
    
    
    
    <category term="HowTo" scheme="https://optinsoft.net/blog/categories/HowTo/"/>
    
    
    <category term="chrome" scheme="https://optinsoft.net/blog/tags/chrome/"/>
    
    <category term="howto" scheme="https://optinsoft.net/blog/tags/howto/"/>
    
    <category term="wattpad" scheme="https://optinsoft.net/blog/tags/wattpad/"/>
    
    <category term="tutorial" scheme="https://optinsoft.net/blog/tags/tutorial/"/>
    
    <category term="developer tools" scheme="https://optinsoft.net/blog/tags/developer-tools/"/>
    
  </entry>
  
  <entry>
    <title>Accelerating Proxy Checks with Async Tasks Per Thread</title>
    <link href="https://optinsoft.net/blog/2026/06/15/Accelerating-Proxy-Checks-with-Async-Tasks-Per-Thread/"/>
    <id>https://optinsoft.net/blog/2026/06/15/Accelerating-Proxy-Checks-with-Async-Tasks-Per-Thread/</id>
    <published>2026-06-15T14:37:35.000Z</published>
    <updated>2026-06-15T14:45:23.032Z</updated>
    
    <content type="html"><![CDATA[<p>One of the fastest ways to check large proxy lists in <a href="/wpc/">Web Proxy Checker</a> is to use the <strong>Async Tasks Per Thread</strong> option.</p><p>Web Proxy Checker is a multi-threaded application. In the <strong>Check Threads</strong> setting, you can define how many worker threads will be used during proxy verification. A thread is an independent execution unit that can process tasks in parallel with other threads.</p><p>When <strong>Async Tasks Per Thread</strong> is enabled, each thread can handle multiple proxy checks simultaneously. Instead of waiting for one proxy request to finish before starting the next one, the thread launches several asynchronous tasks and processes many connections at the same time.</p><p>For example:</p><ul><li>Check Threads: <strong>20</strong></li><li>Async Tasks Per Thread: <strong>50</strong></li></ul><p>This means that up to <strong>20 × 50 &#x3D; 1,000 asynchronous proxy checks</strong> can run concurrently.</p><p>The result is a significant speed increase, especially when checking large proxy lists. In real-world usage, verifying a list of <strong>2,000 proxies</strong> takes roughly <strong>30 seconds</strong>, depending on proxy quality, target settings, and network conditions.</p><p>If you’re working with large proxy databases, enabling asynchronous tasks is one of the most effective ways to maximize checking performance.</p>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;p&gt;One of the fastest ways to check large proxy lists in &lt;a href=&quot;/wpc/&quot;&gt;Web Proxy Checker&lt;/a&gt; is to use the &lt;strong&gt;Async Tasks Per</summary>
        
      
    
    
    
    <category term="Web Proxy Checker" scheme="https://optinsoft.net/blog/categories/Web-Proxy-Checker/"/>
    
    
    <category term="multithreading" scheme="https://optinsoft.net/blog/tags/multithreading/"/>
    
    <category term="proxy" scheme="https://optinsoft.net/blog/tags/proxy/"/>
    
    <category term="async" scheme="https://optinsoft.net/blog/tags/async/"/>
    
    <category term="tasks" scheme="https://optinsoft.net/blog/tags/tasks/"/>
    
    <category term="threads" scheme="https://optinsoft.net/blog/tags/threads/"/>
    
  </entry>
  
  <entry>
    <title>Traffic Caching in ProxyMapService</title>
    <link href="https://optinsoft.net/blog/2026/06/15/Traffic-Caching-in-ProxyMapService/"/>
    <id>https://optinsoft.net/blog/2026/06/15/Traffic-Caching-in-ProxyMapService/</id>
    <published>2026-06-15T05:29:05.000Z</published>
    <updated>2026-06-15T05:38:15.146Z</updated>
    
    <content type="html"><![CDATA[<p>One of the less obvious costs of running large-scale proxy infrastructure is bandwidth. Most proxy providers charge based on traffic usage, so repeatedly downloading the same resources can quickly become expensive.</p><p>To help reduce those costs, ProxyMapService includes an HTTP response caching feature. When enabled, frequently requested resources can be served directly from the local cache instead of being downloaded through the upstream proxy again. In many scenarios this significantly reduces bandwidth consumption and lowers operating costs.</p><h2 id="Enabling-the-Cache"><a href="#Enabling-the-Cache" class="headerlink" title="Enabling the Cache"></a>Enabling the Cache</h2><p>Caching is disabled by default. To enable it, set <code>Enabled</code> to <code>true</code> in the <code>Cache</code> section of <code>appsettings.json</code>:</p><pre><code class="hljs json"><span class="hljs-attr">&quot;Cache&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span>    <span class="hljs-attr">&quot;Enabled&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;DbPath&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;c:\\temp\\cache\\proxymap.db&quot;</span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;CacheDir&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;c:\\temp\\cache\\files&quot;</span><span class="hljs-punctuation">&#125;</span></code></pre><p>Configuration options:</p><table><thead><tr><th>Setting</th><th>Description</th></tr></thead><tbody><tr><td><code>Enabled</code></td><td>Enables or disables caching.</td></tr><tr><td><code>DbPath</code></td><td>Path to the SQLite database used to store cache metadata.</td></tr><tr><td><code>CacheDir</code></td><td>Directory where cached response bodies are stored.</td></tr></tbody></table><h2 id="What-Gets-Cached"><a href="#What-Gets-Cached" class="headerlink" title="What Gets Cached"></a>What Gets Cached</h2><p>ProxyMapService only caches responses that meet all of the following conditions:</p><ul><li>The request method is <code>GET</code></li><li>The response status code is <code>200 OK</code></li><li>The response contains a valid content length</li><li>The response matches a configured cache rule</li><li>The response is considered cacheable according to the cache policy evaluation process</li></ul><p>This approach avoids storing dynamic or non-cacheable content while keeping the cache efficient.</p><h2 id="Cache-Storage-Structure"><a href="#Cache-Storage-Structure" class="headerlink" title="Cache Storage Structure"></a>Cache Storage Structure</h2><p>Cached responses are split into two parts:</p><h3 id="Metadata"><a href="#Metadata" class="headerlink" title="Metadata"></a>Metadata</h3><p>Metadata is stored in a SQLite table named <code>cache_entries</code>.</p><pre><code class="hljs sql"><span class="hljs-keyword">CREATE TABLE</span> cache_entries(    key TEXT <span class="hljs-keyword">PRIMARY KEY</span>,    host TEXT,    url TEXT,    etag TEXT,    cache_control TEXT,    <span class="hljs-type">date</span> TEXT,    expires TEXT,    last_modified TEXT,    header_length <span class="hljs-type">INTEGER</span>,    content_length <span class="hljs-type">INTEGER</span>,    content_type TEXT,    created_at TEXT,    last_access TEXT)</code></pre><p>The table stores information required to evaluate cache validity, including HTTP cache headers such as <code>ETag</code>, <code>Cache-Control</code>, <code>Expires</code>, and <code>Last-Modified</code>.</p><h3 id="Response-Body"><a href="#Response-Body" class="headerlink" title="Response Body"></a>Response Body</h3><p>The actual response content is stored as a binary file under <code>CacheDir</code>.</p><p>Each cache entry receives a SHA-256 key generated from:</p><pre><code class="hljs text">host + url</code></pre><p>Example key:</p><pre><code class="hljs text">18c97f79e87cdfdd7fd0cce3048cc6643b18ed7b154efe859d9fab09209d012a</code></pre><p>Example cache file location:</p><pre><code class="hljs text">c:\temp\cache\files\18\18c9\18c97f79e87cdfdd7fd0cce3048cc6643b18ed7b154efe859d9fab09209d012a.bin</code></pre><p>The nested directory structure prevents large numbers of files from accumulating in a single folder.</p><h2 id="Defining-Cache-Rules"><a href="#Defining-Cache-Rules" class="headerlink" title="Defining Cache Rules"></a>Defining Cache Rules</h2><p>Caching is controlled through <code>CacheRules</code> configured within a host rule.</p><p>Example:</p><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span>    <span class="hljs-attr">&quot;Pattern&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;gstatic\\.com$&quot;</span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;HostPort&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">443</span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;Action&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Bypass&quot;</span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;DecryptSSL&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;CacheRules&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span>        <span class="hljs-attr">&quot;Items&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>            <span class="hljs-punctuation">&#123;</span>                <span class="hljs-attr">&quot;Pattern&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;/images&quot;</span><span class="hljs-punctuation">,</span>                <span class="hljs-attr">&quot;ContentTypePattern&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;image/&quot;</span><span class="hljs-punctuation">,</span>                <span class="hljs-attr">&quot;MaxAge&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">60</span>            <span class="hljs-punctuation">&#125;</span>        <span class="hljs-punctuation">]</span>    <span class="hljs-punctuation">&#125;</span><span class="hljs-punctuation">&#125;</span></code></pre><p>This configuration instructs ProxyMapService to cache:</p><ul><li>Requests sent to hosts matching <code>gstatic\.com$</code></li><li>URLs matching <code>/images</code></li><li>Responses whose <code>Content-Type</code> matches <code>image/</code></li><li>Responses younger than 60 seconds</li></ul><h2 id="HTTPS-Traffic-Requires-SSL-TLS-Decryption"><a href="#HTTPS-Traffic-Requires-SSL-TLS-Decryption" class="headerlink" title="HTTPS Traffic Requires SSL&#x2F;TLS Decryption"></a>HTTPS Traffic Requires SSL&#x2F;TLS Decryption</h2><p>Notice the following setting:</p><pre><code class="hljs json"><span class="hljs-attr">&quot;DecryptSSL&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span></code></pre><p>This is required when caching HTTPS traffic.</p><p>Without SSL&#x2F;TLS decryption, ProxyMapService cannot inspect the request path, response headers, or content type, making cache decisions impossible.</p><p>If you are not familiar with SSL&#x2F;TLS interception in ProxyMapService, see the previous article, <em><a href="/blog/2026/06/11/SSL-TLS-Traffic-Decryption-in-ProxyMapService/">SSL&#x2F;TLS Traffic Decryption in ProxyMapService</a></em>, which explains the setup process in detail.</p><h2 id="Available-Cache-Rule-Options"><a href="#Available-Cache-Rule-Options" class="headerlink" title="Available Cache Rule Options"></a>Available Cache Rule Options</h2><p>Cache rules support several filters and cache-control options.</p><h3 id="Pattern"><a href="#Pattern" class="headerlink" title="Pattern"></a>Pattern</h3><p>Matches the request URL using a regular expression.</p><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span>    <span class="hljs-attr">&quot;Pattern&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;/images&quot;</span><span class="hljs-punctuation">&#125;</span></code></pre><p>Only requests whose URL matches the expression are considered.</p><h3 id="AcceptPattern"><a href="#AcceptPattern" class="headerlink" title="AcceptPattern"></a>AcceptPattern</h3><p>Matches the request’s <code>Accept</code> header.</p><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span>    <span class="hljs-attr">&quot;AcceptPattern&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;image/&quot;</span><span class="hljs-punctuation">&#125;</span></code></pre><p>This can be useful when the same URL may return different content types depending on client preferences.</p><h3 id="ContentTypePattern"><a href="#ContentTypePattern" class="headerlink" title="ContentTypePattern"></a>ContentTypePattern</h3><p>Matches the response <code>Content-Type</code> header.</p><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span>    <span class="hljs-attr">&quot;ContentTypePattern&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;image/&quot;</span><span class="hljs-punctuation">&#125;</span></code></pre><p>The response must match this pattern before it can be stored or served from cache.</p><h3 id="MaxAge"><a href="#MaxAge" class="headerlink" title="MaxAge"></a>MaxAge</h3><p>Defines a fixed lifetime in seconds.</p><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span>    <span class="hljs-attr">&quot;MaxAge&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">3600</span><span class="hljs-punctuation">&#125;</span></code></pre><p>In this example, cached content expires one hour after it is stored.</p><p>When <code>MaxAge</code> is specified, ProxyMapService calculates:</p><pre><code class="hljs text">CreatedAt + MaxAge</code></pre><p>If the current time exceeds that value, the cache entry is treated as expired regardless of any HTTP cache headers.</p><h3 id="IgnoreCacheControl"><a href="#IgnoreCacheControl" class="headerlink" title="IgnoreCacheControl"></a>IgnoreCacheControl</h3><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span>    <span class="hljs-attr">&quot;IgnoreCacheControl&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span><span class="hljs-punctuation">&#125;</span></code></pre><p>When enabled, ProxyMapService ignores the server’s <code>Cache-Control</code>, <code>Expires</code>, and validation directives.</p><p>Only the rule’s <code>MaxAge</code> setting determines whether the cached response can be used.</p><p>This can be useful when caching content from servers that provide overly restrictive cache headers.</p><h2 id="How-Cache-Validation-Works"><a href="#How-Cache-Validation-Works" class="headerlink" title="How Cache Validation Works"></a>How Cache Validation Works</h2><p>When a cached entry is requested, ProxyMapService evaluates whether the entry can still be used.</p><p>The evaluation process follows standard HTTP caching semantics.</p><h3 id="1-Cache-Control-no-store"><a href="#1-Cache-Control-no-store" class="headerlink" title="1. Cache-Control: no-store"></a>1. <code>Cache-Control: no-store</code></h3><pre><code class="hljs http"><span class="hljs-attribute">Cache-Control</span><span class="hljs-punctuation">: </span>no-store</code></pre><p>The response must never be reused.</p><p>Result:</p><pre><code class="hljs text">Refresh</code></pre><p>The content is downloaded again from the origin server.</p><h3 id="2-Cache-Control-no-cache"><a href="#2-Cache-Control-no-cache" class="headerlink" title="2. Cache-Control: no-cache"></a>2. <code>Cache-Control: no-cache</code></h3><pre><code class="hljs http"><span class="hljs-attribute">Cache-Control</span><span class="hljs-punctuation">: </span>no-cache</code></pre><p>The response may be stored, but it must be revalidated before use.</p><p>If the response contains validators such as <code>ETag</code> or <code>Last-Modified</code>:</p><pre><code class="hljs text">Revalidate</code></pre><p>Otherwise:</p><pre><code class="hljs text">Refresh</code></pre><h3 id="3-Freshness-Lifetime-Calculation"><a href="#3-Freshness-Lifetime-Calculation" class="headerlink" title="3. Freshness Lifetime Calculation"></a>3. Freshness Lifetime Calculation</h3><p>ProxyMapService determines freshness using the following priority order.</p><h4 id="max-age"><a href="#max-age" class="headerlink" title="max-age"></a><code>max-age</code></h4><pre><code class="hljs http"><span class="hljs-attribute">Cache-Control</span><span class="hljs-punctuation">: </span>max-age=3600</code></pre><p>This has the highest priority.</p><h4 id="Expires"><a href="#Expires" class="headerlink" title="Expires"></a><code>Expires</code></h4><p>If no <code>max-age</code> exists:</p><pre><code class="hljs http"><span class="hljs-attribute">Expires</span><span class="hljs-punctuation">: </span>Wed, 25 Jun 2025 12:00:00 GMT</code></pre><p>The lifetime is calculated as:</p><pre><code class="hljs text">Expires - Date</code></pre><h4 id="Heuristic-Expiration"><a href="#Heuristic-Expiration" class="headerlink" title="Heuristic Expiration"></a>Heuristic Expiration</h4><p>If neither <code>max-age</code> nor <code>Expires</code> exists, ProxyMapService falls back to a heuristic.</p><p>It calculates approximately 10% of:</p><pre><code class="hljs text">Date - Last-Modified</code></pre><p>For example, if a resource was last modified 10 days before the response date, the cache lifetime becomes roughly 1 day.</p><p>If that information is unavailable, a default lifetime of 10 minutes is used.</p><h2 id="Stale-While-Revalidate-Support"><a href="#Stale-While-Revalidate-Support" class="headerlink" title="Stale-While-Revalidate Support"></a>Stale-While-Revalidate Support</h2><p>ProxyMapService also honors the <code>stale-while-revalidate</code> directive.</p><p>Example:</p><pre><code class="hljs http"><span class="hljs-attribute">Cache-Control</span><span class="hljs-punctuation">: </span>max-age=60, stale-while-revalidate=300</code></pre><p>Behavior:</p><ul><li>First 60 seconds → content is considered fresh</li><li>Next 300 seconds → stale content may still be served</li><li>Background revalidation can occur during this period</li></ul><p>This reduces latency and unnecessary traffic while keeping content reasonably fresh.</p><h2 id="Validation-Using-ETag-and-Last-Modified"><a href="#Validation-Using-ETag-and-Last-Modified" class="headerlink" title="Validation Using ETag and Last-Modified"></a>Validation Using ETag and Last-Modified</h2><p>When cached content becomes stale, ProxyMapService checks whether validation information is available.</p><p>Supported validators:</p><pre><code class="hljs http"><span class="hljs-attribute">ETag</span><span class="hljs-punctuation">: </span>&quot;abc123&quot;</code></pre><p>and</p><pre><code class="hljs http"><span class="hljs-attribute">Last-Modified</span><span class="hljs-punctuation">: </span>Wed, 25 Jun 2025 12:00:00 GMT</code></pre><p>If either validator exists, the entry can be revalidated instead of fully downloaded again.</p><p>This often results in a lightweight HTTP validation request rather than retransferring the entire resource.</p><h2 id="Typical-Use-Cases"><a href="#Typical-Use-Cases" class="headerlink" title="Typical Use Cases"></a>Typical Use Cases</h2><p>Traffic caching is especially effective for:</p><ul><li>Images</li><li>JavaScript bundles</li><li>CSS files</li><li>Fonts</li><li>Static CDN content</li><li>Frequently requested API responses with predictable cache headers</li></ul><p>A common pattern is to cache content from CDN providers such as Google Static Content, Cloudflare, or other asset delivery networks.</p><h2 id="Final-Thoughts"><a href="#Final-Thoughts" class="headerlink" title="Final Thoughts"></a>Final Thoughts</h2><p>For environments where proxy traffic directly affects operating costs, caching can provide immediate savings. By storing frequently requested resources locally and honoring standard HTTP caching semantics, ProxyMapService reduces bandwidth consumption while still respecting content freshness rules.</p><p>In practice, even a small set of well-targeted cache rules for static assets can significantly reduce upstream traffic and improve response times for clients.</p>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;p&gt;One of the less obvious costs of running large-scale proxy infrastructure is bandwidth. Most proxy providers charge based on traffic</summary>
        
      
    
    
    
    <category term="ProxyMapService" scheme="https://optinsoft.net/blog/categories/ProxyMapService/"/>
    
    
    <category term="proxy" scheme="https://optinsoft.net/blog/tags/proxy/"/>
    
    <category term="caching" scheme="https://optinsoft.net/blog/tags/caching/"/>
    
    <category term="http-cache" scheme="https://optinsoft.net/blog/tags/http-cache/"/>
    
    <category term="cost-optimization" scheme="https://optinsoft.net/blog/tags/cost-optimization/"/>
    
    <category term="bandwidth-optimization" scheme="https://optinsoft.net/blog/tags/bandwidth-optimization/"/>
    
  </entry>
  
  <entry>
    <title>SSL/TLS Traffic Decryption in ProxyMapService</title>
    <link href="https://optinsoft.net/blog/2026/06/11/SSL-TLS-Traffic-Decryption-in-ProxyMapService/"/>
    <id>https://optinsoft.net/blog/2026/06/11/SSL-TLS-Traffic-Decryption-in-ProxyMapService/</id>
    <published>2026-06-11T12:02:41.000Z</published>
    <updated>2026-06-11T12:08:45.335Z</updated>
    
    <content type="html"><![CDATA[<p>Most web traffic today is encrypted using HTTPS. While encryption protects data in transit, it also prevents a proxy from inspecting the actual HTTP requests and responses.</p><p>This becomes important when you want ProxyMapService to do more than simple forwarding. For example, caching static content such as images, JavaScript files, stylesheets, fonts, or other assets requires access to the decrypted HTTP payload. Without SSL&#x2F;TLS decryption, the proxy can only see an encrypted byte stream and cannot analyze or cache the content.</p><p>ProxyMapService supports SSL&#x2F;TLS traffic decryption by operating as a man-in-the-middle (MITM) proxy. This allows HTTPS traffic to be inspected, modified, cached, or routed using the same rule engine that is available for regular HTTP traffic.</p><p>ProxyMapService already includes support for content caching, but that topic deserves its own article. In this post, we’ll focus only on SSL&#x2F;TLS decryption and the certificate configuration required to make it work.</p><h2 id="Creating-a-Root-CA-Certificate"><a href="#Creating-a-Root-CA-Certificate" class="headerlink" title="Creating a Root CA Certificate"></a>Creating a Root CA Certificate</h2><p>Before ProxyMapService can decrypt HTTPS traffic, it must be able to generate certificates for target hosts dynamically. To do that, a trusted root Certificate Authority (CA) certificate is required.</p><p>The easiest way to create one is to use the <code>CreateRootCA</code> console utility included with ProxyMapService.</p><p>By default, the utility creates the certificate files in the <code>.proxymap</code> directory located in the current user’s home folder.</p><p>The generated files include:</p><ul><li>A PKCS#12 (<code>.p12</code>) file containing the certificate and private key</li><li>A public certificate (<code>.cer</code>)</li><li>A PEM-encoded public certificate (<code>.pem</code>)</li></ul><h2 id="Installing-the-Certificate"><a href="#Installing-the-Certificate" class="headerlink" title="Installing the Certificate"></a>Installing the Certificate</h2><p>The generated certificate must be installed into the appropriate Windows certificate store.</p><h3 id="Stand-alone-Mode"><a href="#Stand-alone-Mode" class="headerlink" title="Stand-alone Mode"></a>Stand-alone Mode</h3><p>If ProxyMapService is running as a stand-alone application (<code>ProxyMapService.exe</code>), install the root certificate into the <strong>Trusted Root Certification Authorities</strong> store of the <strong>Current User</strong>.</p><p>Open the certificate manager:</p><pre><code class="hljs text">certmgr.msc</code></pre><p>Then import the generated root certificate into:</p><pre><code class="hljs text">Current User └─ Trusted Root Certification Authorities</code></pre><h3 id="IIS-Hosting"><a href="#IIS-Hosting" class="headerlink" title="IIS Hosting"></a>IIS Hosting</h3><p>If ProxyMapService is hosted by IIS, install the certificate into the <strong>Personal</strong> certificate store of the <strong>Local Computer</strong>.</p><p>Open:</p><pre><code class="hljs text">certlm.msc</code></pre><p>Then import the certificate into:</p><pre><code class="hljs text">Local Computer └─ Personal</code></pre><p>The application pool identity must have access to the certificate’s private key.</p><h2 id="Configuring-the-Root-Certificate"><a href="#Configuring-the-Root-Certificate" class="headerlink" title="Configuring the Root Certificate"></a>Configuring the Root Certificate</h2><p>After the certificate has been installed, ProxyMapService must be configured to locate it.</p><p>Example configuration:</p><pre><code class="hljs json"><span class="hljs-attr">&quot;SslServerOptions&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span>    <span class="hljs-attr">&quot;EnabledSslProtocols&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Tls11,Tls12,Tls13&quot;</span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;ClientCertificateRequired&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;CheckCertificateRevocation&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;CACertificate&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span>        <span class="hljs-attr">&quot;StoreLocation&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;LocalMachine&quot;</span><span class="hljs-punctuation">,</span>        <span class="hljs-attr">&quot;StoreName&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;My&quot;</span><span class="hljs-punctuation">,</span>        <span class="hljs-attr">&quot;Subject&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;CN=DO_NOT_TRUST_ProxyMapRoot&quot;</span>    <span class="hljs-punctuation">&#125;</span><span class="hljs-punctuation">&#125;</span></code></pre><p>In this example, ProxyMapService searches for a certificate with the following subject:</p><pre><code class="hljs text">CN=DO_NOT_TRUST_ProxyMapRoot</code></pre><p>inside the <strong>My (Personal)</strong> certificate store of the <strong>Local Machine</strong> certificate location.</p><h2 id="Understanding-SslServerOptions"><a href="#Understanding-SslServerOptions" class="headerlink" title="Understanding SslServerOptions"></a>Understanding SslServerOptions</h2><p><code>SslServerOptions</code> controls how ProxyMapService behaves when acting as the TLS server toward connecting clients.</p><h3 id="EnabledSslProtocols"><a href="#EnabledSslProtocols" class="headerlink" title="EnabledSslProtocols"></a>EnabledSslProtocols</h3><p>Specifies which TLS protocol versions are allowed.</p><pre><code class="hljs json"><span class="hljs-attr">&quot;EnabledSslProtocols&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Tls11,Tls12,Tls13&quot;</span></code></pre><p>Only the listed protocol versions will be accepted during TLS negotiation.</p><p>In most environments, TLS 1.2 and TLS 1.3 are sufficient. TLS 1.1 is typically enabled only for compatibility with legacy clients.</p><h3 id="ClientCertificateRequired"><a href="#ClientCertificateRequired" class="headerlink" title="ClientCertificateRequired"></a>ClientCertificateRequired</h3><p>Controls whether the client must present a certificate during the TLS handshake.</p><pre><code class="hljs json"><span class="hljs-attr">&quot;ClientCertificateRequired&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span></code></pre><p>When set to <code>false</code>, clients authenticate using standard HTTPS behavior.</p><p>When set to <code>true</code>, mutual TLS (mTLS) is required and clients must provide a valid certificate.</p><h3 id="CheckCertificateRevocation"><a href="#CheckCertificateRevocation" class="headerlink" title="CheckCertificateRevocation"></a>CheckCertificateRevocation</h3><p>Controls certificate revocation checking.</p><pre><code class="hljs json"><span class="hljs-attr">&quot;CheckCertificateRevocation&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span></code></pre><p>When enabled, Windows performs online revocation checks using CRL or OCSP endpoints during certificate validation.</p><p>Disabling revocation checks can reduce connection latency and avoid failures in isolated environments where revocation services are unavailable.</p><h3 id="CACertificate"><a href="#CACertificate" class="headerlink" title="CACertificate"></a>CACertificate</h3><p>Specifies the root CA certificate used by ProxyMapService to generate certificates for intercepted HTTPS hosts.</p><p>The certificate is identified using:</p><ul><li><code>StoreLocation</code></li><li><code>StoreName</code></li><li><code>Subject</code></li></ul><p>The private key associated with this certificate is required for successful SSL&#x2F;TLS interception.</p><h2 id="Understanding-SslClientOptions"><a href="#Understanding-SslClientOptions" class="headerlink" title="Understanding SslClientOptions"></a>Understanding SslClientOptions</h2><p><code>SslClientOptions</code> controls how ProxyMapService authenticates when connecting to upstream HTTPS servers.</p><p>Example configuration:</p><pre><code class="hljs json"><span class="hljs-attr">&quot;SslClientOptions&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span>    <span class="hljs-attr">&quot;EnabledSslProtocols&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Tls11,Tls12,Tls13&quot;</span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;CheckCertificateRevocation&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span><span class="hljs-punctuation">&#125;</span></code></pre><h3 id="EnabledSslProtocols-1"><a href="#EnabledSslProtocols-1" class="headerlink" title="EnabledSslProtocols"></a>EnabledSslProtocols</h3><p>Specifies which TLS protocol versions ProxyMapService may use when establishing outbound HTTPS connections.</p><pre><code class="hljs json"><span class="hljs-attr">&quot;EnabledSslProtocols&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Tls11,Tls12,Tls13&quot;</span></code></pre><p>Only the configured protocols will be offered during negotiation with the remote server.</p><h3 id="CheckCertificateRevocation-1"><a href="#CheckCertificateRevocation-1" class="headerlink" title="CheckCertificateRevocation"></a>CheckCertificateRevocation</h3><p>Controls revocation checking for certificates presented by upstream servers.</p><pre><code class="hljs json"><span class="hljs-attr">&quot;CheckCertificateRevocation&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span></code></pre><p>When enabled, certificate revocation status is verified before the server certificate is accepted.</p><p>This helps detect certificates that have been revoked by the issuing authority.</p><h2 id="Enabling-SSL-TLS-Decryption"><a href="#Enabling-SSL-TLS-Decryption" class="headerlink" title="Enabling SSL&#x2F;TLS Decryption"></a>Enabling SSL&#x2F;TLS Decryption</h2><p>Once the certificate has been installed and the SSL options are configured, SSL&#x2F;TLS decryption can be enabled using the <code>DecryptSSL</code> setting.</p><p>Decryption can be enabled globally for a listening port or selectively for specific host rules.</p><h3 id="Enabling-Decryption-on-a-Listening-Port"><a href="#Enabling-Decryption-on-a-Listening-Port" class="headerlink" title="Enabling Decryption on a Listening Port"></a>Enabling Decryption on a Listening Port</h3><p>Example:</p><pre><code class="hljs json"><span class="hljs-attr">&quot;Listen&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span>    <span class="hljs-attr">&quot;Port&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">10001</span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;RejectHttpProxy&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;DecryptSSL&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span><span class="hljs-punctuation">&#125;</span></code></pre><p>With this configuration, all HTTPS traffic received on port <code>10001</code> will be decrypted and processed by ProxyMapService.</p><p>This is usually the simplest configuration when all traffic arriving on the listener should be inspected.</p><h2 id="Enabling-Decryption-for-Specific-Hosts"><a href="#Enabling-Decryption-for-Specific-Hosts" class="headerlink" title="Enabling Decryption for Specific Hosts"></a>Enabling Decryption for Specific Hosts</h2><p>Sometimes only a subset of HTTPS traffic needs to be decrypted.</p><p>In that case, decryption can be enabled within host rules.</p><p>Example:</p><pre><code class="hljs json"><span class="hljs-attr">&quot;HostRules&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span>    <span class="hljs-attr">&quot;Items&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>        <span class="hljs-punctuation">&#123;</span>            <span class="hljs-attr">&quot;Pattern&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;google\\.com$&quot;</span><span class="hljs-punctuation">,</span>            <span class="hljs-attr">&quot;HostPort&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">443</span><span class="hljs-punctuation">,</span>            <span class="hljs-attr">&quot;DecryptSSL&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span>        <span class="hljs-punctuation">&#125;</span>    <span class="hljs-punctuation">]</span><span class="hljs-punctuation">&#125;</span></code></pre><p>In this configuration, only HTTPS traffic matching <code>google.com</code> on port <code>443</code> will be decrypted.</p><p>All other HTTPS traffic will continue to pass through without interception.</p><p>This approach is useful when SSL inspection is required only for selected destinations.</p><h2 id="Verifying-the-Configuration"><a href="#Verifying-the-Configuration" class="headerlink" title="Verifying the Configuration"></a>Verifying the Configuration</h2><p>After enabling SSL&#x2F;TLS decryption:</p><ol><li>Start ProxyMapService.</li><li>Configure a browser or application to use the proxy.</li><li>Open an HTTPS website.</li><li>Verify that no certificate warnings are displayed.</li><li>Check ProxyMapService logs to confirm that decrypted HTTP requests and responses are being processed.</li></ol><p>If certificate warnings appear, verify that:</p><ul><li>The root CA certificate is installed in the correct certificate store.</li><li>The configured certificate subject matches the installed certificate.</li><li>The certificate includes a private key.</li><li>The service account has permission to access the private key.</li></ul><h2 id="Conclusion"><a href="#Conclusion" class="headerlink" title="Conclusion"></a>Conclusion</h2><p>SSL&#x2F;TLS decryption is a prerequisite for advanced HTTPS traffic processing in ProxyMapService. Once a trusted root CA certificate is installed and configured, the service can inspect encrypted traffic just as it does regular HTTP traffic.</p><p>This capability enables scenarios such as request inspection, response modification, traffic analysis, selective routing, and content caching. In a future post, we’ll take a closer look at the caching subsystem and how it can be used to efficiently serve static content directly from ProxyMapService.</p>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;p&gt;Most web traffic today is encrypted using HTTPS. While encryption protects data in transit, it also prevents a proxy from inspecting the</summary>
        
      
    
    
    
    <category term="ProxyMapService" scheme="https://optinsoft.net/blog/categories/ProxyMapService/"/>
    
    
    <category term="mitm" scheme="https://optinsoft.net/blog/tags/mitm/"/>
    
    <category term="create-certificate" scheme="https://optinsoft.net/blog/tags/create-certificate/"/>
    
    <category term="ssl" scheme="https://optinsoft.net/blog/tags/ssl/"/>
    
    <category term="tls" scheme="https://optinsoft.net/blog/tags/tls/"/>
    
    <category term="decrypt" scheme="https://optinsoft.net/blog/tags/decrypt/"/>
    
  </entry>
  
  <entry>
    <title>Session API for Sticky Proxy Management in ProxyMapService</title>
    <link href="https://optinsoft.net/blog/2026/06/10/Session-API-for-Sticky-Proxy-Management-in-ProxyMapService/"/>
    <id>https://optinsoft.net/blog/2026/06/10/Session-API-for-Sticky-Proxy-Management-in-ProxyMapService/</id>
    <published>2026-06-10T16:33:26.000Z</published>
    <updated>2026-06-10T16:54:26.899Z</updated>
    
    <content type="html"><![CDATA[<p>In a previous article, <em><a href="/blog/2026/01/16/Making-Any-Scraper-Work-with-Sticky-Proxies/">Making Any Scraper Work with Sticky Proxies</a></em>, we discussed how ProxyMapService maps local ports to independent sticky proxy sessions.</p><p>Each local port automatically receives its own session ID and keeps it for the configured <code>StickyProxyLifetime</code>. This allows applications that only support simple <code>IP:PORT</code> proxies to work with modern session-based proxy providers.</p><p>Until now, session management in ProxyMapService was completely automatic. While this works well for many use cases, some applications need direct control over when sessions are created, rotated, or discarded.</p><p>The latest version of ProxyMapService introduces a Session API that allows applications and scripts to inspect, reset, and create sessions on demand.</p><h2 id="How-sessions-work"><a href="#How-sessions-work" class="headerlink" title="How sessions work"></a>How sessions work</h2><p>Assume the following configuration:</p><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span>  <span class="hljs-attr">&quot;Listen&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span>    <span class="hljs-attr">&quot;PortRange&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span>      <span class="hljs-attr">&quot;Start&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">10201</span><span class="hljs-punctuation">,</span>      <span class="hljs-attr">&quot;End&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">10300</span>    <span class="hljs-punctuation">&#125;</span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;StickyProxyLifetime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">10</span>  <span class="hljs-punctuation">&#125;</span><span class="hljs-punctuation">&#125;</span></code></pre><p>When traffic is sent through port <code>10201</code>, ProxyMapService generates a session ID:</p><pre><code class="hljs plaintext">10201 → session LZpmRqdu</code></pre><p>All requests made through this port will use the same sticky session until it expires.</p><p>The new Session API exposes this information and allows manual control over the session lifecycle.</p><h2 id="Enabling-Session-API"><a href="#Enabling-Session-API" class="headerlink" title="Enabling Session API"></a>Enabling Session API</h2><p>For security and compatibility reasons, Session API is disabled by default.</p><p>To enable it, add the following section to your appsettings.json:</p><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span>  <span class="hljs-attr">&quot;SessionAPI&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span>    <span class="hljs-attr">&quot;Enabled&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;Domain&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;portmapper&quot;</span>  <span class="hljs-punctuation">&#125;</span><span class="hljs-punctuation">&#125;</span></code></pre><h2 id="Configuration-Options"><a href="#Configuration-Options" class="headerlink" title="Configuration Options"></a>Configuration Options</h2><table><thead><tr><th>Option</th><th>Description</th></tr></thead><tbody><tr><td><code>Enabled</code></td><td>Enables Session API endpoints.</td></tr><tr><td><code>Domain</code></td><td>Virtual domain used to access Session API endpoints through a mapped proxy port.</td></tr></tbody></table><p>With the configuration above, Session API can be accessed using requests such as:</p><pre><code class="hljs shell">curl -x http://127.0.0.1:10201 http://portmapper/session/</code></pre><h2 id="Using-an-Empty-Domain"><a href="#Using-an-Empty-Domain" class="headerlink" title="Using an Empty Domain"></a>Using an Empty Domain</h2><p>The Domain setting is optional and may be set to an empty string:</p><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span>  <span class="hljs-attr">&quot;SessionAPI&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span>    <span class="hljs-attr">&quot;Enabled&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;Domain&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;&quot;</span>  <span class="hljs-punctuation">&#125;</span><span class="hljs-punctuation">&#125;</span></code></pre><p>When <code>Domain</code> is empty, Session API endpoints become available directly on the mapped proxy port.</p><p>For example:</p><pre><code class="hljs shell">curl http://127.0.0.1:10201/session/</code></pre><p>This can be convenient when working with local tools or scripts that do not support custom hostnames.</p><h2 id="Get-Current-Session"><a href="#Get-Current-Session" class="headerlink" title="Get Current Session"></a>Get Current Session</h2><p>Returns information about the session currently assigned to a port.</p><p>Example:</p><pre><code class="hljs shell">curl -x http://127.0.0.1:10201 http://portmapper/session/</code></pre><p>Response:</p><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span>  <span class="hljs-attr">&quot;session_id&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;LZpmRqdu&quot;</span><span class="hljs-punctuation">,</span>  <span class="hljs-attr">&quot;expires_at&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Wed, 10 Jun 2026 16:09:43 GMT&quot;</span><span class="hljs-punctuation">,</span>  <span class="hljs-attr">&quot;expired&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span><span class="hljs-punctuation">&#125;</span></code></pre><p>If the session is still active, repeated calls return the same information.</p><p>When the sticky session expires, ProxyMapService automatically generates a new session ID and the endpoint will return the new session details.</p><p>This can be useful for monitoring session state or checking how much time remains before rotation.</p><h2 id="Reset-Current-Session"><a href="#Reset-Current-Session" class="headerlink" title="Reset Current Session"></a>Reset Current Session</h2><p>Sometimes you want to force a session change without waiting for the expiration timer.</p><p>The <code>/session/reset</code> endpoint removes the current session associated with the port.</p><p>Example:</p><pre><code class="hljs shell">curl -x http://127.0.0.1:10201 http://portmapper/session/reset</code></pre><p>Response:</p><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span>  <span class="hljs-attr">&quot;success&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span><span class="hljs-punctuation">&#125;</span></code></pre><p>After the reset, the next request through port 10201 will automatically create a new session.</p><p>Typical use cases:</p><ul><li>detected or blocked IP address</li><li>captcha escalation</li><li>failed scraping workflow</li><li>manual IP rotation</li></ul><h2 id="Create-a-New-Session-Immediately"><a href="#Create-a-New-Session-Immediately" class="headerlink" title="Create a New Session Immediately"></a>Create a New Session Immediately</h2><p>The <code>/session/new</code> endpoint creates a new session immediately and assigns it to the port.</p><p>Example:</p><pre><code class="hljs shell">curl -x http://127.0.0.1:10201 http://portmapper/session/new</code></pre><p>Response:</p><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span>  <span class="hljs-attr">&quot;session_id&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;uawxmttg&quot;</span><span class="hljs-punctuation">,</span>  <span class="hljs-attr">&quot;expires_at&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Wed, 10 Jun 2026 16:19:48 GMT&quot;</span><span class="hljs-punctuation">,</span>  <span class="hljs-attr">&quot;expired&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span><span class="hljs-punctuation">&#125;</span></code></pre><p>Unlike <code>/session/reset</code>, which simply removes the current session, <code>/session/new</code> generates and activates a replacement session instantly.</p><p>This is useful when an application wants to rotate identities proactively while continuing to use the same local proxy port.</p><h2 id="Why-Not-Just-Change-Ports"><a href="#Why-Not-Just-Change-Ports" class="headerlink" title="Why Not Just Change Ports?"></a>Why Not Just Change Ports?</h2><p>A common question is why you would need a Session API if every port already has its own sticky session.</p><p>In practice, many scraping and automation systems assign a specific role to each local proxy port. For example:</p><pre><code class="hljs plaintext">127.0.0.1:10201 → Worker A127.0.0.1:10202 → Worker B127.0.0.1:10203 → Worker C</code></pre><p>Workers may maintain their own queues, browser profiles, cookies, account assignments, or internal state tied to a particular proxy endpoint.</p><p>Changing ports is not always practical because it may require updating application configuration, restarting workers, or reassigning tasks.</p><p>With Session API, the application can keep using the same local proxy port while rotating the underlying sticky session whenever necessary.</p><h2 id="Practical-Examples"><a href="#Practical-Examples" class="headerlink" title="Practical Examples"></a>Practical Examples</h2><p>Session API can be useful when:</p><ul><li>a target website starts returning captchas</li><li>an IP address becomes blocked or rate-limited</li><li>a scraping task needs a fresh identity immediately</li><li>monitoring systems need visibility into session expiration</li><li>applications want explicit control over session rotation timing</li></ul><p>All of this can be done without restarting ProxyMapService and without changing the local proxy endpoint used by the application.</p><h2 id="Summary"><a href="#Summary" class="headerlink" title="Summary"></a>Summary</h2><p>ProxyMapService was originally designed to make sticky proxies available to software that only understands simple <code>IP:PORT</code> proxy lists.</p><p>The new Session API adds direct control over the sticky sessions behind each mapped port.</p><p>Available endpoints:</p><ul><li><code>GET /session/</code> — get information about the current session</li><li><code>GET /session/reset</code> — remove the current session</li><li><code>GET /session/new</code> — create and activate a new session immediately</li></ul><p>This makes it easier to build scraping, automation, and data collection systems that need predictable control over proxy identities while continuing to use ordinary local proxy ports.</p>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;p&gt;In a previous article, &lt;em&gt;&lt;a href=&quot;/blog/2026/01/16/Making-Any-Scraper-Work-with-Sticky-Proxies/&quot;&gt;Making Any Scraper Work with Sticky</summary>
        
      
    
    
    
    <category term="ProxyMapService" scheme="https://optinsoft.net/blog/categories/ProxyMapService/"/>
    
    
    <category term="proxy" scheme="https://optinsoft.net/blog/tags/proxy/"/>
    
    <category term="sticky-proxy" scheme="https://optinsoft.net/blog/tags/sticky-proxy/"/>
    
    <category term="session" scheme="https://optinsoft.net/blog/tags/session/"/>
    
    <category term="api" scheme="https://optinsoft.net/blog/tags/api/"/>
    
  </entry>
  
  <entry>
    <title>Using ProxyMapService to Fix pip Behind SOCKS5 Proxy</title>
    <link href="https://optinsoft.net/blog/2026/03/27/Using-a-Port-Mapper-to-Fix-pip-Behind-SOCKS5-Proxy/"/>
    <id>https://optinsoft.net/blog/2026/03/27/Using-a-Port-Mapper-to-Fix-pip-Behind-SOCKS5-Proxy/</id>
    <published>2026-03-27T04:46:41.000Z</published>
    <updated>2026-03-27T05:16:37.378Z</updated>
    
    <content type="html"><![CDATA[<p>I ran into an issue where <code>pip</code> wasn’t working due to network restrictions. At the same time, I had access to a SOCKS5 proxy at:</p><pre><code class="hljs plaintext">192.168.1.100:1080</code></pre><p>The problem was that <code>pip</code> doesn’t support SOCKS proxies out of the box. Normally, you’d install <code>PySocks</code> to enable that — but since <code>pip</code> itself wasn’t working, that wasn’t an option.</p><p>I used the <a href="https://github.com/optinsoft/ProxyMapService">ProxyMapService</a> to expose the SOCKS5 proxy as a local HTTP proxy. Here’s the rule I configured:</p><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span>  <span class="hljs-attr">&quot;Listen&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span>    <span class="hljs-attr">&quot;Port&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">10000</span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;RejectHttpProxy&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span>  <span class="hljs-punctuation">&#125;</span><span class="hljs-punctuation">,</span>  <span class="hljs-attr">&quot;Authentication&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span>    <span class="hljs-attr">&quot;Required&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;Verify&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;SetAuthentication&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span>  <span class="hljs-punctuation">&#125;</span><span class="hljs-punctuation">,</span>  <span class="hljs-attr">&quot;ProxyServers&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span>    <span class="hljs-attr">&quot;Items&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>      <span class="hljs-punctuation">&#123;</span>        <span class="hljs-attr">&quot;Host&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;192.168.1.100&quot;</span><span class="hljs-punctuation">,</span>        <span class="hljs-attr">&quot;Port&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1080</span><span class="hljs-punctuation">,</span>        <span class="hljs-attr">&quot;ProxyType&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Socks5&quot;</span>      <span class="hljs-punctuation">&#125;</span>    <span class="hljs-punctuation">]</span>  <span class="hljs-punctuation">&#125;</span><span class="hljs-punctuation">&#125;</span></code></pre><p>After that, <code>pip</code> started working by pointing it to the local HTTP proxy:</p><pre><code class="hljs plaintext">pip install cython --proxy http://127.0.0.1:10000Collecting cython  Using cached cython-3.2.4-cp311-cp311-win_amd64.whl.metadata (7.7 kB)Using cached cython-3.2.4-cp311-cp311-win_amd64.whl (2.8 MB)Installing collected packages: cythonSuccessfully installed cython-3.2.4</code></pre><p>🎉</p>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;p&gt;I ran into an issue where &lt;code&gt;pip&lt;/code&gt; wasn’t working due to network restrictions. At the same time, I had access to a SOCKS5 proxy</summary>
        
      
    
    
    
    <category term="ProxyMapService" scheme="https://optinsoft.net/blog/categories/ProxyMapService/"/>
    
    
    <category term="proxy" scheme="https://optinsoft.net/blog/tags/proxy/"/>
    
    <category term="socks5" scheme="https://optinsoft.net/blog/tags/socks5/"/>
    
    <category term="pip" scheme="https://optinsoft.net/blog/tags/pip/"/>
    
  </entry>
  
  <entry>
    <title>Making Any Scraper Work with Sticky Proxies</title>
    <link href="https://optinsoft.net/blog/2026/01/16/Making-Any-Scraper-Work-with-Sticky-Proxies/"/>
    <id>https://optinsoft.net/blog/2026/01/16/Making-Any-Scraper-Work-with-Sticky-Proxies/</id>
    <published>2026-01-16T06:45:20.000Z</published>
    <updated>2026-01-16T07:37:49.843Z</updated>
    
    <content type="html"><![CDATA[<h1 id="How-to-Use-Sticky-Proxies-in-Applications-That-Don’t-Support-Them"><a href="#How-to-Use-Sticky-Proxies-in-Applications-That-Don’t-Support-Them" class="headerlink" title="How to Use Sticky Proxies in Applications That Don’t Support Them"></a>How to Use Sticky Proxies in Applications That Don’t Support Them</h1><p>Many modern proxy providers sell so-called <strong>sticky proxies</strong> (also known as session-based proxies). This is a very popular solution for scraping, automation, data collection, and working around anti-bot protections.</p><h2 id="What-is-a-sticky-proxy"><a href="#What-is-a-sticky-proxy" class="headerlink" title="What is a sticky proxy?"></a>What is a sticky proxy?</h2><p>A <strong>sticky proxy</strong> is a proxy server that “locks” one IP address to you for a certain amount of time (for example, 5 or 10 minutes) using a session. Usually, the session is defined via the username, for example:</p><pre><code class="hljs plaintext">user-session-ABC123-sessTime-10:password@proxy_host:proxy_port</code></pre><p>While the session is active, you will access the internet from the same IP address. When the time expires or you change the session ID, you get a new IP.</p><p>Today, <strong>most large proxy providers</strong> (residential, mobile, ISP) work exactly this way: you connect to a single host and port, and IP rotation is controlled via parameters in the username.</p><h2 id="The-problem-not-all-software-supports-sticky-proxies"><a href="#The-problem-not-all-software-supports-sticky-proxies" class="headerlink" title="The problem: not all software supports sticky proxies"></a>The problem: not all software supports sticky proxies</h2><p>Many applications (scraping software, old parsers, bots, automation tools):</p><ul><li>❌ cannot work with proxies that require authentication  </li><li>❌ cannot manage sessions  </li><li>❌ expect <strong>just a list of IP:PORT</strong>, without username and password</li></ul><p>Because of this, they cannot be directly connected to modern sticky proxy providers.</p><h2 id="The-solution-map-local-TCP-ports-through-sticky-proxies"><a href="#The-solution-map-local-TCP-ports-through-sticky-proxies" class="headerlink" title="The solution: map local TCP ports through sticky proxies"></a>The solution: map local TCP ports through sticky proxies</h2><p>The idea is very simple:</p><ul><li>We run a local service</li><li>It opens a <strong>range of local ports</strong></li><li>Each local port:<ul><li>automatically connects to the sticky proxy</li><li>uses <strong>its own separate session</strong></li></ul></li><li>As a result:<ul><li><code>127.0.0.1:5001</code> → sticky proxy session AAA1  </li><li><code>127.0.0.1:5002</code> → sticky proxy session AAA2  </li><li><code>127.0.0.1:5003</code> → sticky proxy session AAA3  </li><li>and so on</li></ul></li></ul><p>And your software just works with regular proxies without authentication:</p><pre><code class="hljs plaintext">127.0.0.1:5001127.0.0.1:5002127.0.0.1:5003</code></pre><h2 id="Ready-made-solution-ProxyMapService"><a href="#Ready-made-solution-ProxyMapService" class="headerlink" title="Ready-made solution: ProxyMapService"></a>Ready-made solution: ProxyMapService</h2><p>For this purpose, the following open-source project works perfectly:</p><p>👉 <strong>ProxyMapService</strong><br><a href="https://github.com/optinsoft/ProxyMapService">https://github.com/optinsoft/ProxyMapService</a></p><p>It can:</p><ul><li>map port ranges</li><li>automatically manage sticky sessions</li><li>work with HTTP &#x2F; SOCKS proxies</li><li>modify &#x2F; generate username parameters</li></ul><h2 id="Configuration-example"><a href="#Configuration-example" class="headerlink" title="Configuration example"></a>Configuration example</h2><p>Here is an example config:</p><pre><code class="hljs json"><span class="hljs-attr">&quot;ProxyMappings&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>  <span class="hljs-punctuation">&#123;</span>    <span class="hljs-attr">&quot;Listen&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span>      <span class="hljs-attr">&quot;PortRange&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span>        <span class="hljs-attr">&quot;Start&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">10001</span><span class="hljs-punctuation">,</span>        <span class="hljs-attr">&quot;End&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">10100</span>      <span class="hljs-punctuation">&#125;</span><span class="hljs-punctuation">,</span>      <span class="hljs-attr">&quot;RejectHttpProxy&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span><span class="hljs-punctuation">,</span>      <span class="hljs-attr">&quot;StickyProxyLifetime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">10</span>    <span class="hljs-punctuation">&#125;</span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;Authentication&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span>      <span class="hljs-attr">&quot;Required&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span><span class="hljs-punctuation">,</span>      <span class="hljs-attr">&quot;Verify&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span><span class="hljs-punctuation">,</span>      <span class="hljs-attr">&quot;SetAuthentication&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span><span class="hljs-punctuation">,</span>      <span class="hljs-attr">&quot;RemoveAuthentication&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">false</span></span>    <span class="hljs-punctuation">&#125;</span><span class="hljs-punctuation">,</span>    <span class="hljs-attr">&quot;ProxyServers&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span>      <span class="hljs-attr">&quot;Items&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>        <span class="hljs-punctuation">&#123;</span>          <span class="hljs-attr">&quot;Host&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;PROXY_IP&quot;</span><span class="hljs-punctuation">,</span>          <span class="hljs-attr">&quot;Port&quot;</span><span class="hljs-punctuation">:</span> PROXY_PORT<span class="hljs-punctuation">,</span>          <span class="hljs-attr">&quot;ProxyType&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Http&quot;</span><span class="hljs-punctuation">,</span>          <span class="hljs-attr">&quot;Username&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;USERNAME&quot;</span><span class="hljs-punctuation">,</span>          <span class="hljs-attr">&quot;Password&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;PASSWORD&quot;</span><span class="hljs-punctuation">,</span>          <span class="hljs-attr">&quot;UsernameParameters&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>            <span class="hljs-punctuation">&#123;</span>              <span class="hljs-attr">&quot;Name&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;zone&quot;</span><span class="hljs-punctuation">,</span>              <span class="hljs-attr">&quot;Value&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;custom&quot;</span>            <span class="hljs-punctuation">&#125;</span><span class="hljs-punctuation">,</span>            <span class="hljs-punctuation">&#123;</span>              <span class="hljs-attr">&quot;Name&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;region&quot;</span><span class="hljs-punctuation">,</span>              <span class="hljs-attr">&quot;Value&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;US&quot;</span>            <span class="hljs-punctuation">&#125;</span><span class="hljs-punctuation">,</span>            <span class="hljs-punctuation">&#123;</span>              <span class="hljs-attr">&quot;Name&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;session&quot;</span><span class="hljs-punctuation">,</span>              <span class="hljs-attr">&quot;Value&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;^[A-Za-z]&#123;8&#125;&quot;</span><span class="hljs-punctuation">,</span>              <span class="hljs-attr">&quot;SessionId&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span>            <span class="hljs-punctuation">&#125;</span><span class="hljs-punctuation">,</span>            <span class="hljs-punctuation">&#123;</span>              <span class="hljs-attr">&quot;Name&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;sessTime&quot;</span><span class="hljs-punctuation">,</span>              <span class="hljs-attr">&quot;Value&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;$sessTime&quot;</span><span class="hljs-punctuation">,</span>              <span class="hljs-attr">&quot;Default&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;10&quot;</span><span class="hljs-punctuation">,</span>              <span class="hljs-attr">&quot;SessionTime&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-literal"><span class="hljs-keyword">true</span></span>            <span class="hljs-punctuation">&#125;</span>          <span class="hljs-punctuation">]</span>        <span class="hljs-punctuation">&#125;</span>      <span class="hljs-punctuation">]</span>    <span class="hljs-punctuation">&#125;</span>  <span class="hljs-punctuation">&#125;</span><span class="hljs-punctuation">]</span></code></pre><p>⚠️ In this example you need to replace:</p><ul><li><code>PROXY_IP</code></li><li><code>PROXY_PORT</code></li><li><code>USERNAME</code></li><li><code>PASSWORD</code></li></ul><p>with the values provided by your proxy provider.</p><h2 id="How-does-it-work-in-practice"><a href="#How-does-it-work-in-practice" class="headerlink" title="How does it work in practice?"></a>How does it work in practice?</h2><ul><li><p>ProxyMapService opens local ports <code>10001–10100</code></p></li><li><p>Each port:</p><ul><li>automatically generates a new sticky session</li><li>keeps it for <code>StickyProxyLifetime = 10</code> minutes</li></ul></li><li><p>You just set in your software:</p></li></ul><pre><code class="hljs plaintext">127.0.0.1:10001127.0.0.1:10002127.0.0.1:10003...</code></pre><h2 id="Conclusion"><a href="#Conclusion" class="headerlink" title="Conclusion"></a>Conclusion</h2><p>If your software:</p><ul><li>doesn’t support proxy authentication</li><li>doesn’t support sessions</li><li>only works with <code>IP:PORT</code> lists</li></ul><p>➡️ <strong>ProxyMapService solves this problem completely</strong>, allowing you to use modern sticky proxies without modifying your software.</p><p>Useful for:</p><ul><li>scraping software</li><li>bots</li><li>automation tools</li><li>legacy tools</li><li>and basically any software with poor proxy support</li></ul>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;h1 id=&quot;How-to-Use-Sticky-Proxies-in-Applications-That-Don’t-Support-Them&quot;&gt;&lt;a</summary>
        
      
    
    
    
    <category term="ProxyMapService" scheme="https://optinsoft.net/blog/categories/ProxyMapService/"/>
    
    
    <category term="sticky-proxy" scheme="https://optinsoft.net/blog/tags/sticky-proxy/"/>
    
    <category term="proxy-server" scheme="https://optinsoft.net/blog/tags/proxy-server/"/>
    
    <category term="rotating-proxy" scheme="https://optinsoft.net/blog/tags/rotating-proxy/"/>
    
    <category term="scraping" scheme="https://optinsoft.net/blog/tags/scraping/"/>
    
    <category term="proxy-rotation" scheme="https://optinsoft.net/blog/tags/proxy-rotation/"/>
    
    <category term="session-based-proxy" scheme="https://optinsoft.net/blog/tags/session-based-proxy/"/>
    
  </entry>
  
  <entry>
    <title>ProxyMapService: ParseUsernameParameters</title>
    <link href="https://optinsoft.net/blog/2025/12/19/ProxyMapService-ParseUsernameParameters/"/>
    <id>https://optinsoft.net/blog/2025/12/19/ProxyMapService-ParseUsernameParameters/</id>
    <published>2025-12-19T10:33:06.000Z</published>
    <updated>2026-01-16T06:55:33.414Z</updated>
    
    <content type="html"><![CDATA[<p>We’re excited to announce a new, optional feature in the <strong><a href="https://github.com/optinsoft/ProxyMapService">ProxyMapService</a></strong> application. This feature enhances the flexibility of the authentication process by allowing you to simplify username validation.</p><h2 id="The-Challenge-Managing-Complex-Usernames"><a href="#The-Challenge-Managing-Complex-Usernames" class="headerlink" title="The Challenge: Managing Complex Usernames"></a>The Challenge: Managing Complex Usernames</h2><p>Sometimes, proxy usernames need to encode more information than just the account identifier. </p><p>For example, a proxy might look like this:</p><p><a href="http://user-zone-custom-region-US-session-1234567-sessionTime-5:1111@127.0.0.1:8888/">http://user-zone-custom-region-US-session-1234567-sessionTime-5:1111@127.0.0.1:8888</a></p><p>Username part of the proxy is <code>user-zone-custom-region-US-session-1234567-sessionTime-5</code>.</p><p>While this format might be necessary for other parts of the system or for identification, it complicates the standard authentication process by requiring the system to ignore the extra parts (<code>zone</code>, <code>region</code>, <code>session</code>, etc.) and focus solely on the actual username.</p><h2 id="The-Solution-Introducing-ParseUsernameParameters"><a href="#The-Solution-Introducing-ParseUsernameParameters" class="headerlink" title="The Solution: Introducing ParseUsernameParameters"></a>The Solution: Introducing <code>ParseUsernameParameters</code></h2><p>To address this need for cleaner authentication, we’ve introduced a new configuration parameter called <strong><code>ParseUsernameParameters</code></strong>. This boolean parameter resides within the <code>Authentication</code> section of the <code>appsettings.json</code> file.</p><ul><li><strong>Parameter Name:</strong> <code>ParseUsernameParameters</code></li><li><strong>Allowed Values:</strong> <code>true</code> or <code>false</code> (default is <code>false</code>)</li></ul><h3 id="What-Does-This-Parameter-Do"><a href="#What-Does-This-Parameter-Do" class="headerlink" title="What Does This Parameter Do?"></a>What Does This Parameter Do?</h3><p>When set to <code>true</code>, the <code>ProxyMapService</code> will parse the username string during authentication. It splits the username using the hyphen (<code>-</code>) delimiter. <strong>Crucially, only the first segment (the part <em>before</em> the first hyphen) is used for the authentication check.</strong> The remaining segments are ignored.</p><h3 id="How-It-Works-Example"><a href="#How-It-Works-Example" class="headerlink" title="How It Works (Example)"></a>How It Works (Example)</h3><p>Let’s take a look at the authentication logic with <code>ParseUsernameParameters=true</code>:</p><ol><li><p><strong>Input Username (part of the proxy):</strong></p><pre><code class="hljs plaintext">&quot;user-zone-custom-region-US-session-1234567-sessionTime-5&quot;</code></pre></li><li><p><strong>Authentication Logic (with <code>ParseUsernameParameters=true</code>):</strong></p><ul><li>The username string <code>user-zone-custom-region-US-session-1234567-sessionTime-5</code> is split using the <code>-</code> character.</li><li>The resulting parts are: <code>[&quot;user&quot;, &quot;zone&quot;, &quot;custom&quot;, &quot;region&quot;, &quot;US&quot;, &quot;session&quot;, &quot;1234567&quot;, &quot;sessionTime&quot;, &quot;5&quot;]</code></li><li><strong>Authentication Check:</strong> The system compares the <em>first part</em>, <code>user</code>, to the configured <code>Username</code> value (e.g., <code>&quot;user&quot;</code> from the example config). The rest of the parts are completely ignored for authentication.</li></ul></li></ol><h3 id="Configuration-Example-appsettings-json"><a href="#Configuration-Example-appsettings-json" class="headerlink" title="Configuration Example (appsettings.json)"></a>Configuration Example (<code>appsettings.json</code>)</h3><p>Here’s how you would enable this feature in your <code>appsettings.json</code>:</p><pre><code class="language-json">&#123;  &quot;Authentication&quot;: &#123;    // ... other authentication settings ...    &quot;Required&quot;: true,    &quot;Verify&quot;: true,    &quot;ParseUsernameParameters&quot;: true,    &quot;Username&quot;: &quot;user&quot;,  // This is the base username to compare against    &quot;Password&quot;: &quot;1111&quot;    // Password  &#125;&#125;</code></pre>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;p&gt;We’re excited to announce a new, optional feature in the &lt;strong&gt;&lt;a</summary>
        
      
    
    
    
    <category term="ProxyMapService" scheme="https://optinsoft.net/blog/categories/ProxyMapService/"/>
    
    
    <category term="Authentication" scheme="https://optinsoft.net/blog/tags/Authentication/"/>
    
    <category term="ParseUsernameParameters" scheme="https://optinsoft.net/blog/tags/ParseUsernameParameters/"/>
    
  </entry>
  
  <entry>
    <title>Web Proxy Checker v2.111 Released</title>
    <link href="https://optinsoft.net/blog/2025/12/11/Web-Proxy-Checker-v2-111-Released/"/>
    <id>https://optinsoft.net/blog/2025/12/11/Web-Proxy-Checker-v2-111-Released/</id>
    <published>2025-12-11T09:21:38.000Z</published>
    <updated>2025-12-11T09:41:19.703Z</updated>
    
    <content type="html"><![CDATA[<h1 id="Enhanced-Authentication-for-Problematic-Proxies"><a href="#Enhanced-Authentication-for-Problematic-Proxies" class="headerlink" title="Enhanced Authentication for Problematic Proxies"></a>Enhanced Authentication for Problematic Proxies</h1><p>We’re pleased to announce the release of <strong><a href="/wpc/">Web Proxy Checker version 2.111</a></strong> – our reliable tool for testing proxy server functionality now includes improved handling for CONNECT (HTTPS) proxies with non-standard authentication behavior.</p><h2 id="Standard-Proxy-Authentication-Flow"><a href="#Standard-Proxy-Authentication-Flow" class="headerlink" title="Standard Proxy Authentication Flow"></a>Standard Proxy Authentication Flow</h2><p>When connecting to a proxy requiring Basic Authentication, the expected protocol is:</p><ol><li>Client (browser or our tool) connects without credentials</li><li>Proxy responds with “407 Proxy Authentication Required”</li><li>Client reconnects with the Proxy-Authorization HTTP header</li><li>Connection proceeds if credentials are valid</li></ol><p>This standard flow is used by all major browsers (Chrome, Firefox, Edge) and has been Web Proxy Checker’s default behavior.</p><h2 id="The-Challenge-Non-Compliant-Proxies"><a href="#The-Challenge-Non-Compliant-Proxies" class="headerlink" title="The Challenge: Non-Compliant Proxies"></a>The Challenge: Non-Compliant Proxies</h2><p>During testing, we identified proxies that don’t follow authentication standards. Instead of returning the proper 407 error, they immediately close connections when credentials are missing. This creates a compatibility issue where legitimate authentication attempts fail.</p><h2 id="New-Feature-“Connect-Basic-Authentication”-Setting"><a href="#New-Feature-“Connect-Basic-Authentication”-Setting" class="headerlink" title="New Feature: “Connect Basic Authentication” Setting"></a>New Feature: “Connect Basic Authentication” Setting</h2><p>Version 2.111 introduces a solution on the <strong>HTTP</strong> tab: the new <strong>“Connect Basic Authentication”</strong> option.</p><h3 id="How-it-works"><a href="#How-it-works" class="headerlink" title="How it works:"></a>How it works:</h3><ul><li><strong>Disabled (Default)</strong>: Standard behavior – waits for 407 response before sending credentials</li><li><strong>Enabled</strong>: Immediately includes Proxy-Authorization header in the first connection attempt</li><li><strong>Result</strong>: Compatibility with proxies that require immediate authentication</li></ul><h2 id="Usage-Recommendations"><a href="#Usage-Recommendations" class="headerlink" title="Usage Recommendations:"></a>Usage Recommendations:</h2><ul><li>Most users should keep this setting disabled (works with standard proxies)</li><li>Enable only when encountering proxies that close connections without 407 responses</li><li>Particularly useful for certain corporate or custom proxy setups</li></ul><h2 id="Quick-Setup"><a href="#Quick-Setup" class="headerlink" title="Quick Setup:"></a>Quick Setup:</h2><ol><li>Launch Web Proxy Checker v2.111</li><li>Go to the <strong>HTTP</strong> tab</li><li>Find <strong>“Connect Basic Authentication”</strong> checkbox</li><li>Enable for problematic proxies, disable for standard ones</li></ol><h2 id="What-This-Means-for-You"><a href="#What-This-Means-for-You" class="headerlink" title="What This Means for You:"></a>What This Means for You:</h2><ul><li>✓ Wider proxy compatibility</li><li>✓ No more failed connections with non-standard proxies</li><li>✓ Backward compatibility maintained</li><li>✓ Easy toggle between authentication modes</li></ul><h2 id="Upgrade-Today"><a href="#Upgrade-Today" class="headerlink" title="Upgrade Today"></a>Upgrade Today</h2><p><strong><a href="/wpc/">Download Web Proxy Checker v2.111</a></strong> and experience improved compatibility with all your proxy servers!</p>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;h1 id=&quot;Enhanced-Authentication-for-Problematic-Proxies&quot;&gt;&lt;a href=&quot;#Enhanced-Authentication-for-Problematic-Proxies&quot; class=&quot;headerlink&quot;</summary>
        
      
    
    
    
    <category term="Web Proxy Checker" scheme="https://optinsoft.net/blog/categories/Web-Proxy-Checker/"/>
    
    
    <category term="WebProxyChecker" scheme="https://optinsoft.net/blog/tags/WebProxyChecker/"/>
    
    <category term="v2111" scheme="https://optinsoft.net/blog/tags/v2111/"/>
    
    <category term="Update" scheme="https://optinsoft.net/blog/tags/Update/"/>
    
    <category term="ProxyAuthorization" scheme="https://optinsoft.net/blog/tags/ProxyAuthorization/"/>
    
  </entry>
  
  <entry>
    <title>ProxyMapService Diagnostics in Windows Event Log</title>
    <link href="https://optinsoft.net/blog/2025/10/28/ProxyMapService-Diagnostics-in-Windows-Event-Log/"/>
    <id>https://optinsoft.net/blog/2025/10/28/ProxyMapService-Diagnostics-in-Windows-Event-Log/</id>
    <published>2025-10-28T15:52:38.000Z</published>
    <updated>2026-01-16T06:51:07.293Z</updated>
    
    <content type="html"><![CDATA[<p><strong><a href="https://github.com/optinsoft/ProxyMapService">ProxyMapService</a></strong> now supports outputting diagnostic messages directly to the <strong>Windows Event Log</strong>.</p><hr><h3 id="1-Enabling-Event-Log-Logging"><a href="#1-Enabling-Event-Log-Logging" class="headerlink" title="1. Enabling Event Log Logging"></a>1. Enabling Event Log Logging</h3><p>To enable writing events to the Windows Event Log, you need to make a small change in your project’s configuration file — <code>appsettings.json</code>.</p><p>Add the <code>EventLog</code> section within the <code>Logging</code> block, specifying the desired minimum logging level. The example below sets the level to <strong>“Information”</strong>:</p><pre><code class="hljs json"><span class="hljs-punctuation">&#123;</span>  <span class="hljs-attr">&quot;Logging&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span>    <span class="hljs-attr">&quot;EventLog&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span>      <span class="hljs-attr">&quot;LogLevel&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">&#123;</span>        <span class="hljs-attr">&quot;Default&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;Information&quot;</span>      <span class="hljs-punctuation">&#125;</span>    <span class="hljs-punctuation">&#125;</span>  <span class="hljs-punctuation">&#125;</span><span class="hljs-punctuation">&#125;</span></code></pre><blockquote><p>💡 <strong>Note:</strong> The <code>Default</code> level within the <code>EventLog</code> section determines the minimum level (Trace, Debug, Information, Warning, Error, Critical) at which messages will be written to the log.</p></blockquote><hr><h3 id="2-Mandatory-Step-Registering-the-Event-Source-PowerShell"><a href="#2-Mandatory-Step-Registering-the-Event-Source-PowerShell" class="headerlink" title="2. Mandatory Step: Registering the Event Source (PowerShell)"></a>2. Mandatory Step: Registering the Event Source (PowerShell)</h3><p><strong>Attention!</strong> For messages to be successfully displayed in the Event Log and for the system to correctly identify their source and formatting, it is <strong>necessary to register the event source</strong> with the name <code>ProxyMapService</code> beforehand.</p><p>Event source registration is <strong>only required once</strong> upon installation or update of the service.</p><p>Use <strong>PowerShell run as administrator</strong> and execute the following command. This command creates the necessary registry key:</p><pre><code class="hljs powershell"><span class="hljs-built_in">New-EventLog</span> <span class="hljs-literal">-LogName</span> Application <span class="hljs-literal">-Source</span> ProxyMapService</code></pre><ul><li><code>New-EventLog</code>: The cmdlet used to create a new event source.</li><li><code>-LogName Application</code>: Specifies that the source will write to the standard “Application” log.</li><li><code>-Source ProxyMapService</code>: Sets the source name, which must match the name used within the service code.</li></ul><hr><h3 id="3-Viewing-the-Events"><a href="#3-Viewing-the-Events" class="headerlink" title="3. Viewing the Events"></a>3. Viewing the Events</h3><p>After configuring <code>appsettings.json</code> and registering the source, restart the <strong>ProxyMapService</strong>. All events at the <code>Information</code> level and above will now be available for viewing in the <strong>Windows Event Viewer</strong> under <strong>Windows Logs</strong> $\rightarrow$ <strong>Application</strong>.</p><p>Look for messages with the <strong>Source</strong>: <code>ProxyMapService</code>.</p><p><strong>🔗 Source Code and Discussion:</strong> As always, you can find the latest version of the project on GitHub: <a href="https://github.com/optinsoft/ProxyMapService">https://github.com/optinsoft/ProxyMapService</a></p>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;p&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/optinsoft/ProxyMapService&quot;&gt;ProxyMapService&lt;/a&gt;&lt;/strong&gt; now supports outputting diagnostic messages</summary>
        
      
    
    
    
    <category term="ProxyMapService" scheme="https://optinsoft.net/blog/categories/ProxyMapService/"/>
    
    
    <category term="EventLog" scheme="https://optinsoft.net/blog/tags/EventLog/"/>
    
    <category term="Windows" scheme="https://optinsoft.net/blog/tags/Windows/"/>
    
  </entry>
  
  <entry>
    <title>CountryTimezone</title>
    <link href="https://optinsoft.net/blog/2025/10/14/CountryTimezone/"/>
    <id>https://optinsoft.net/blog/2025/10/14/CountryTimezone/</id>
    <published>2025-10-14T09:54:51.000Z</published>
    <updated>2025-10-14T10:23:15.325Z</updated>
    
    <content type="html"><![CDATA[<p>If you’ve worked with timezones in Python, you’ve probably used pytz to get IANA timezone names for specific countries:</p><pre><code class="hljs python">tz_names = pytz.country_timezones.get(country.upper(), [])</code></pre><p>When I needed similar functionality in Delphi, I was surprised to find that there wasn’t a readily available library to get IANA timezone names for countries.</p><p>After searching without success, I decided to create my own solution:</p><p><a href="https://github.com/optinsoft/CountryTimezone"><strong>https://github.com/optinsoft/CountryTimezone</strong></a></p><p>Here’s a practical example that demonstrates how to get a random timezone name and its UTC offset for a given country:</p><pre><code class="hljs pascal"><span class="hljs-keyword">uses</span> CountryTimezone, TZDB;<span class="hljs-keyword">type</span>   TTimezoneAndOffset = <span class="hljs-keyword">record</span>        <span class="hljs-keyword">name</span>: <span class="hljs-keyword">String</span>;        offset: Integer;   <span class="hljs-keyword">end</span>;<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">GetRandomTimezoneAndOffset</span><span class="hljs-params">(country: <span class="hljs-keyword">String</span>)</span>:</span> TTimezoneAndOffset;<span class="hljs-keyword">var</span>  LCTZDict: TCountryTimezoneDictionary;  LCTZList: TStringList;  tz: TBundledTimeZone;<span class="hljs-keyword">begin</span>  LCTZDict := TCountryTimezoneDictionary.Create();  LCTZList := TStringList.Create;  <span class="hljs-keyword">try</span>    LCTZDict.GetCountryTimezones(country, LCTZList);    Result.<span class="hljs-keyword">name</span> := LCTZList[Random(LCTZList.Count)];    tz := TBundledTimeZone.GetTimeZone(Result.<span class="hljs-keyword">name</span>);    Result.offset := Trunc(tz.UtcOffset.TotalMinutes);  <span class="hljs-keyword">finally</span>    LCTZList.Free;    LCTZDict.Free;  <span class="hljs-keyword">end</span>;<span class="hljs-keyword">end</span>;</code></pre><p>This function:</p><ol><li>Creates a country timezone dictionary</li><li>Retrieves all timezone names for the specified country</li><li>Selects a random timezone from the list</li><li>Uses TZDB to get the UTC offset in minutes for that timezone</li></ol>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;p&gt;If you’ve worked with timezones in Python, you’ve probably used pytz to get IANA timezone names for specific countries:&lt;/p&gt;
&lt;pre&gt;&lt;code</summary>
        
      
    
    
    
    <category term="GitHub" scheme="https://optinsoft.net/blog/categories/GitHub/"/>
    
    
    <category term="delphi" scheme="https://optinsoft.net/blog/tags/delphi/"/>
    
    <category term="TZDB" scheme="https://optinsoft.net/blog/tags/TZDB/"/>
    
    <category term="country" scheme="https://optinsoft.net/blog/tags/country/"/>
    
    <category term="timezone" scheme="https://optinsoft.net/blog/tags/timezone/"/>
    
  </entry>
  
  <entry>
    <title>renamedecl</title>
    <link href="https://optinsoft.net/blog/2025/10/10/renamedecl/"/>
    <id>https://optinsoft.net/blog/2025/10/10/renamedecl/</id>
    <published>2025-10-10T14:35:07.000Z</published>
    <updated>2025-10-10T15:24:57.715Z</updated>
    
    <content type="html"><![CDATA[<h1 id="🔄-Renaming-Variables-and-Functions-in-JavaScript-Using-ASTs"><a href="#🔄-Renaming-Variables-and-Functions-in-JavaScript-Using-ASTs" class="headerlink" title="🔄 Renaming Variables and Functions in JavaScript Using ASTs"></a>🔄 Renaming Variables and Functions in JavaScript Using ASTs</h1><p>When working with JavaScript, there are times you might want to automatically rename variables or functions across your code — perhaps for <strong>obfuscation</strong>, <strong>code transformation</strong>, or <strong>refactoring</strong>. Doing this safely, without accidentally breaking your program, requires understanding how your code is structured — and that’s where the <strong>Abstract Syntax Tree (AST)</strong> comes in.</p><p>In this post, we’ll look at how to rename variable and function declarations using ASTs, with a simple utility <a href="https://github.com/optinsoft/renamedecl">renamedecl</a>.</p><hr><h2 id="🌳-What-Is-an-AST"><a href="#🌳-What-Is-an-AST" class="headerlink" title="🌳 What Is an AST?"></a>🌳 What Is an AST?</h2><p>An <strong>Abstract Syntax Tree (AST)</strong> is a structured, tree-like representation of your source code.<br>Instead of dealing with raw text, you work with objects that represent <strong>program constructs</strong> like variables, functions, loops, and expressions.</p><p>For example, the code:</p><pre><code class="hljs js"><span class="hljs-keyword">const</span> x = <span class="hljs-number">5</span>;<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(x);</code></pre><p>can be represented (simplified) as:</p><pre><code class="hljs js">&#123;  <span class="hljs-attr">type</span>: <span class="hljs-string">&quot;Program&quot;</span>,  <span class="hljs-attr">body</span>: [    &#123;      <span class="hljs-attr">type</span>: <span class="hljs-string">&quot;VariableDeclaration&quot;</span>,      <span class="hljs-attr">declarations</span>: [        &#123;          <span class="hljs-attr">type</span>: <span class="hljs-string">&quot;VariableDeclarator&quot;</span>,          <span class="hljs-attr">id</span>: &#123; <span class="hljs-attr">type</span>: <span class="hljs-string">&quot;Identifier&quot;</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">&quot;x&quot;</span> &#125;,          <span class="hljs-attr">init</span>: &#123; <span class="hljs-attr">type</span>: <span class="hljs-string">&quot;Literal&quot;</span>, <span class="hljs-attr">value</span>: <span class="hljs-number">5</span> &#125;        &#125;      ]    &#125;,    &#123;      <span class="hljs-attr">type</span>: <span class="hljs-string">&quot;ExpressionStatement&quot;</span>,      <span class="hljs-attr">expression</span>: &#123;        <span class="hljs-attr">type</span>: <span class="hljs-string">&quot;CallExpression&quot;</span>,        <span class="hljs-attr">callee</span>: &#123;          <span class="hljs-attr">object</span>: &#123; <span class="hljs-attr">name</span>: <span class="hljs-string">&quot;console&quot;</span> &#125;,          <span class="hljs-attr">property</span>: &#123; <span class="hljs-attr">name</span>: <span class="hljs-string">&quot;log&quot;</span> &#125;        &#125;,        <span class="hljs-attr">arguments</span>: [&#123; <span class="hljs-attr">type</span>: <span class="hljs-string">&quot;Identifier&quot;</span>, <span class="hljs-attr">name</span>: <span class="hljs-string">&quot;x&quot;</span> &#125;]      &#125;    &#125;  ]&#125;</code></pre><p>By working with this structure, you can programmatically modify parts of your code (e.g. change <code>x</code> to <code>width</code>) and then regenerate valid JavaScript source code.</p><hr><h2 id="🧩-Tools-Acorn-Escodegen"><a href="#🧩-Tools-Acorn-Escodegen" class="headerlink" title="🧩 Tools: Acorn, Escodegen"></a>🧩 Tools: Acorn, Escodegen</h2><ul><li><strong><a href="https://github.com/acornjs/acorn">Acorn</a></strong> — a fast, lightweight JavaScript parser. It converts JS source code into an AST.</li><li><strong><a href="https://github.com/estools/escodegen">Escodegen</a></strong> — generates readable JavaScript code from an AST.</li></ul><h2 id="Scopes"><a href="#Scopes" class="headerlink" title="Scopes"></a>Scopes</h2><p><strong>Scopes</strong> — just like in real code, variables and functions in an AST exist within <strong>scopes</strong> (e.g., global, function, block). When renaming identifiers, you need to make sure you don’t accidentally rename a variable from an outer scope that has the same name.</p><hr><h2 id="🚀-Introducing-renamedecl"><a href="#🚀-Introducing-renamedecl" class="headerlink" title="🚀 Introducing renamedecl"></a>🚀 Introducing <code>renamedecl</code></h2><p><strong><a href="https://github.com/optinsoft/renamedecl">renamedecl</a></strong> is the lightweight tool for renaming variables and functions in JS code based on an AST.</p><p>The function <code>renameDeclarations(ast, rename, initscope?)</code> walks through your AST, finds all <strong>declarations</strong> (variables, function names, parameters, etc.), and lets you rename them safely according to the rules you define.</p><p>It can be used in two main ways:</p><hr><h3 id="1-Automatic-Renaming"><a href="#1-Automatic-Renaming" class="headerlink" title="1. Automatic Renaming"></a>1. Automatic Renaming</h3><p>You can rename every variable and function in a consistent way — for example, to obfuscate or anonymize code.</p><pre><code class="hljs js"><span class="hljs-keyword">const</span> acorn = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;acorn&#x27;</span>);<span class="hljs-keyword">const</span> escodegen = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;escodegen&#x27;</span>);<span class="hljs-keyword">const</span> &#123; renameDeclarations &#125; = <span class="hljs-built_in">require</span>(<span class="hljs-string">&#x27;renamedecl&#x27;</span>);<span class="hljs-keyword">const</span> originalCode = <span class="hljs-string">`</span><span class="hljs-string">function add(x, y) &#123;</span><span class="hljs-string">    const result = x + y;</span><span class="hljs-string">    return result;</span><span class="hljs-string">&#125;</span><span class="hljs-string">`</span>;<span class="hljs-keyword">const</span> ast = acorn.<span class="hljs-title function_">parse</span>(originalCode, &#123;    <span class="hljs-attr">ecmaVersion</span>: <span class="hljs-number">2020</span>,    <span class="hljs-attr">sourceType</span>: <span class="hljs-string">&#x27;script&#x27;</span>&#125;);<span class="hljs-comment">// Rename all identifiers sequentially</span><span class="hljs-title function_">renameDeclarations</span>(    ast,    <span class="hljs-function">(<span class="hljs-params">id, scope</span>) =&gt;</span> <span class="hljs-string">`v<span class="hljs-subst">$&#123;++scope.varNum&#125;</span>`</span>,    <span class="hljs-function"><span class="hljs-params">scope</span> =&gt;</span> &#123; scope.<span class="hljs-property">varNum</span> = <span class="hljs-number">0</span>; &#125;);<span class="hljs-keyword">const</span> newCode = escodegen.<span class="hljs-title function_">generate</span>(ast);<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(newCode);</code></pre><p><strong>Output:</strong></p><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">v1</span>(<span class="hljs-params">v2, v3</span>) &#123;    <span class="hljs-keyword">const</span> v1 = v2 + v3;    <span class="hljs-keyword">return</span> v1;&#125;</code></pre><p>Here, every declared identifier got renamed with a consistent numbering scheme, respecting the correct scope hierarchy.</p><hr><h3 id="2-Custom-Rename-Mapping"><a href="#2-Custom-Rename-Mapping" class="headerlink" title="2. Custom Rename Mapping"></a>2. Custom Rename Mapping</h3><p>You can also define your own rename map to transform specific variable or function names.</p><pre><code class="hljs js"><span class="hljs-keyword">const</span> renameMap = &#123;    <span class="hljs-attr">x</span>: <span class="hljs-string">&#x27;width&#x27;</span>,    <span class="hljs-attr">y</span>: <span class="hljs-string">&#x27;height&#x27;</span>,    <span class="hljs-attr">result</span>: <span class="hljs-string">&#x27;sum&#x27;</span>&#125;;<span class="hljs-title function_">renameDeclarations</span>(ast, <span class="hljs-function"><span class="hljs-params">id</span> =&gt;</span> renameMap[id.<span class="hljs-property">name</span>]);</code></pre><p>This is great for <strong>refactoring</strong>, such as renaming variables to more meaningful names.</p><hr><h2 id="🧠-How-Scoping-Works"><a href="#🧠-How-Scoping-Works" class="headerlink" title="🧠 How Scoping Works"></a>🧠 How Scoping Works</h2><p><strong><a href="https://github.com/optinsoft/renamedecl"><code>renamedecl</code></a></strong> automatically tracks <strong>scopes</strong> as it traverses the AST.<br>When it enters a new function or block, it creates a new scope object.<br>This ensures that two variables named <code>x</code> in different functions don’t get mixed up:</p><pre><code class="hljs js"><span class="hljs-keyword">function</span> <span class="hljs-title function_">outer</span>(<span class="hljs-params"></span>) &#123;    <span class="hljs-keyword">const</span> x = <span class="hljs-number">10</span>;    <span class="hljs-keyword">function</span> <span class="hljs-title function_">inner</span>(<span class="hljs-params"></span>) &#123;        <span class="hljs-keyword">const</span> x = <span class="hljs-number">20</span>;        <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(x);    &#125;    <span class="hljs-title function_">inner</span>();&#125;</code></pre><p>Both <code>x</code> variables live in different scopes. The renaming logic keeps that distinction intact — so each gets its own renamed version.</p><hr><h2 id="🔧-Why-Use-This"><a href="#🔧-Why-Use-This" class="headerlink" title="🔧 Why Use This?"></a>🔧 Why Use This?</h2><ul><li>✅ <strong>Safe</strong> — Respects JavaScript scoping rules</li><li>🔍 <strong>Customizable</strong> — You control the renaming logic</li><li>🧰 <strong>Tool-friendly</strong> — Works directly with standard AST tools</li><li>⚙️ <strong>Flexible</strong> — Use it for obfuscation, refactoring, or static analysis</li></ul><hr><h2 id="🧩-Try-It-Out"><a href="#🧩-Try-It-Out" class="headerlink" title="🧩 Try It Out"></a>🧩 Try It Out</h2><p>You can install it via npm:</p><pre><code class="hljs bash">npm install git+https://github.com/optinsoft/renamedecl.git</code></pre><p>Then import and use it as shown above.</p><hr><h2 id="💡-Conclusion"><a href="#💡-Conclusion" class="headerlink" title="💡 Conclusion"></a>💡 Conclusion</h2><p>Working with ASTs may sound intimidating at first, but with tools like <strong>Acorn</strong>, <strong>Escodegen</strong>, and utilities such as <strong><a href="https://github.com/optinsoft/renamedecl"><code>renamedecl</code></a></strong>, transforming JavaScript code becomes powerful and approachable.</p><p>By controlling variable and function names at the AST level, you can safely build tools for <strong>code analysis</strong>, <strong>transpilation</strong>, <strong>refactoring</strong>, or <strong>obfuscation</strong> — all while preserving the correctness of your original code.</p>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;h1 id=&quot;🔄-Renaming-Variables-and-Functions-in-JavaScript-Using-ASTs&quot;&gt;&lt;a</summary>
        
      
    
    
    
    <category term="GitHub" scheme="https://optinsoft.net/blog/categories/GitHub/"/>
    
    
    <category term="AST" scheme="https://optinsoft.net/blog/tags/AST/"/>
    
    <category term="javascript" scheme="https://optinsoft.net/blog/tags/javascript/"/>
    
  </entry>
  
  <entry>
    <title>How to download a Chrome extension without installing it</title>
    <link href="https://optinsoft.net/blog/2025/10/08/How-to-download-a-Chrome-extension-without-installing-it/"/>
    <id>https://optinsoft.net/blog/2025/10/08/How-to-download-a-Chrome-extension-without-installing-it/</id>
    <published>2025-10-08T14:56:36.000Z</published>
    <updated>2025-10-08T15:41:17.991Z</updated>
    
    <content type="html"><![CDATA[<ol><li>In the Chrome Web Store, find the extension you need, for example, uBlock Origin.</li><li>The extension’s URL looks like this: <code>https://chromewebstore.google.com/detail/ublock/epcnnfbjfcgphgdmggkamkmgojdagdnn?hl=en-US&amp;utm_source=ext_sidebar</code>. The part <code>epcnnfbjfcgphgdmggkamkmgojdagdnn</code> is the extension’s unique ID.</li><li>Find out your version of Chrome, for example, <code>141.0.7390.55</code>.</li><li>Use CURL to get the extension’s download link, replacing the extension ID (<code>epcnnfbjfcgphgdmggkamkmgojdagdnn</code>) and Chrome version (<code>141.0.7390.55</code>) with your own values:<pre><code class="hljs bash">curl <span class="hljs-string">&quot;https://clients2.google.com/service/update2/crx?response=redirect&amp;os=win&amp;arch=x64&amp;os_arch=x86_64&amp;prod=chromecrx&amp;prodchannel=&amp;prodversion=141.0.7390.55&amp;lang=en-US&amp;acceptformat=crx3,puff&amp;x=id%3Depcnnfbjfcgphgdmggkamkmgojdagdnn%26installsource%3Dondemand%26uc&amp;authuser=0&quot;</span></code></pre></li><li>The result of the previous CURL command will look something like this:<pre><code class="hljs html"><span class="hljs-tag">&lt;<span class="hljs-name">HTML</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">HEAD</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">TITLE</span>&gt;</span>Moved Temporarily<span class="hljs-tag">&lt;/<span class="hljs-name">TITLE</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">HEAD</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">BODY</span> <span class="hljs-attr">BGCOLOR</span>=<span class="hljs-string">&quot;#FFFFFF&quot;</span> <span class="hljs-attr">TEXT</span>=<span class="hljs-string">&quot;#000000&quot;</span>&gt;</span><span class="hljs-comment">&lt;!-- GSE Default Error --&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">H1</span>&gt;</span>Moved Temporarily<span class="hljs-tag">&lt;/<span class="hljs-name">H1</span>&gt;</span>The document has moved <span class="hljs-tag">&lt;<span class="hljs-name">A</span> <span class="hljs-attr">HREF</span>=<span class="hljs-string">&quot;https://clients2.googleusercontent.com/crx/blobs/AcLY-yQ8Sxe7u0UiOxVYs1X2QxXnl4NGRAS6t4jJr_viP7fvXl9ARlV4ETIu1woz6O7cdB3-RBD9cYdV3APCdHY8S6kBmmk5mSnRTo0LZ8FUJQEkbk_6NnrX0EPLsAaqxNK-AMZSmuUQPLnhgEjCRn4So0hrUrRuyQSHOA/EPCNNFBJFCGPHGDMGGKAMKMGOJDAGDNN_25_5_0_0.crx?authuser=0&quot;</span>&gt;</span>here<span class="hljs-tag">&lt;/<span class="hljs-name">A</span>&gt;</span>.<span class="hljs-tag">&lt;/<span class="hljs-name">BODY</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">HTML</span>&gt;</span></code></pre>The URL from which you can download the extension is: <code>https://clients2.googleusercontent.com/crx/blobs/AcLY-yQ8Sxe7u0UiOxVYs1X2QxXnl4NGRAS6t4jJr_viP7fvXl9ARlV4ETIu1woz6O7cdB3-RBD9cYdV3APCdHY8S6kBmmk5mSnRTo0LZ8FUJQEkbk_6NnrX0EPLsAaqxNK-AMZSmuUQPLnhgEjCRn4So0hrUrRuyQSHOA/EPCNNFBJFCGPHGDMGGKAMKMGOJDAGDNN_25_5_0_0.crx?authuser=0</code></li><li>Use CURL to download the CRX file:<pre><code class="hljs bash">curl <span class="hljs-string">&quot;https://clients2.googleusercontent.com/crx/blobs/AcLY-yQ8Sxe7u0UiOxVYs1X2QxXnl4NGRAS6t4jJr_viP7fvXl9ARlV4ETIu1woz6O7cdB3-RBD9cYdV3APCdHY8S6kBmmk5mSnRTo0LZ8FUJQEkbk_6NnrX0EPLsAaqxNK-AMZSmuUQPLnhgEjCRn4So0hrUrRuyQSHOA/EPCNNFBJFCGPHGDMGGKAMKMGOJDAGDNN_25_5_0_0.crx?authuser=0&quot;</span> --output uBlock.crx</code></pre></li></ol>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;ol&gt;
&lt;li&gt;In the Chrome Web Store, find the extension you need, for example, uBlock Origin.&lt;/li&gt;
&lt;li&gt;The extension’s URL looks like this:</summary>
        
      
    
    
    
    <category term="HowTo" scheme="https://optinsoft.net/blog/categories/HowTo/"/>
    
    
    <category term="chrome" scheme="https://optinsoft.net/blog/tags/chrome/"/>
    
    <category term="extension" scheme="https://optinsoft.net/blog/tags/extension/"/>
    
    <category term="howto" scheme="https://optinsoft.net/blog/tags/howto/"/>
    
  </entry>
  
  <entry>
    <title>gen_eth and gen_trx updates</title>
    <link href="https://optinsoft.net/blog/2025/09/18/gen-eth-and-gen-trx-updates/"/>
    <id>https://optinsoft.net/blog/2025/09/18/gen-eth-and-gen-trx-updates/</id>
    <published>2025-09-18T09:27:48.000Z</published>
    <updated>2025-09-18T10:12:02.962Z</updated>
    
    <content type="html"><![CDATA[<p>After installing the NVIDIA GPU Computing Toolkit v13, the <a href="https://github.com/optinsoft/gen_eth">gen_eth</a> and <a href="https://github.com/optinsoft/gen_trx">gen_trx</a> projects started producing an error:</p><pre><code class="hljs plaintext">ImportError: DLL load failed while importing _driver: DLL load failed</code></pre><p>The reason is that <code>pycuda</code> is trying to load the CUDA DLL from the <code>bin</code> directory:</p><pre><code class="hljs plaintext">C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.0\bin</code></pre><p>I am using the latest version of <code>pycuda</code> available at the moment: v2025.1.2.</p><p><code>pycuda\driver.py</code>:</p><pre><code class="hljs plaintext">def _add_cuda_libdir_to_dll_path():from os.path import dirname, jointextcuda_path = os.environ.get(&quot;CUDA_PATH&quot;)if cuda_path is not None:    os.add_dll_directory(join(cuda_path, &quot;bin&quot;))    return</code></pre><p>However, in version v13 of the NVIDIA GPU Computing Toolkit, the DLLs are located in the <code>bin\x64</code> directory:</p><pre><code class="hljs plaintext">C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.0\bin\x64</code></pre><p>To solve this problem, a new setting CUDA_DLL_PATH has been added to settings.ini, which contains the full path to the CUDA DLL.</p><p><code>settings.ini</code>:</p><pre><code class="hljs plaintext">[settings]CL_PATH=C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\bin\Hostx64\x64CUDA_DLL_PATH=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.0\bin\x64</code></pre><p>The latest versions of gen_eth and gen_trx are available on GitHub:</p><ul><li><a href="https://github.com/optinsoft/gen_eth">https://github.com/optinsoft/gen_eth</a></li><li><a href="https://github.com/optinsoft/gen_trx">https://github.com/optinsoft/gen_trx</a></li></ul><p>PS. If the following error occurs:</p><pre><code class="hljs plaintext">pycuda._driver.LogicError: cuModuleLoadDataEx failed: device kernel image is invalid</code></pre><p>then you need to update the NVIDIA video driver: <a href="https://www.nvidia.com/en-us/drivers/">https://www.nvidia.com/en-us/drivers/</a></p>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;p&gt;After installing the NVIDIA GPU Computing Toolkit v13, the &lt;a href=&quot;https://github.com/optinsoft/gen_eth&quot;&gt;gen_eth&lt;/a&gt; and &lt;a</summary>
        
      
    
    
    
    <category term="GitHub" scheme="https://optinsoft.net/blog/categories/GitHub/"/>
    
    
    <category term="CUDA" scheme="https://optinsoft.net/blog/tags/CUDA/"/>
    
    <category term="pycuda" scheme="https://optinsoft.net/blog/tags/pycuda/"/>
    
  </entry>
  
  <entry>
    <title>Blog migrated to Hexo</title>
    <link href="https://optinsoft.net/blog/2025/09/12/Blog-migrated-to-Hexo/"/>
    <id>https://optinsoft.net/blog/2025/09/12/Blog-migrated-to-Hexo/</id>
    <published>2025-09-12T13:29:35.000Z</published>
    <updated>2025-09-13T14:51:03.161Z</updated>
    
    <content type="html"><![CDATA[<p>This blog has been migrated from WordPress to Hexo.</p><p>For the blog migration, I wrote a powershell script called wp-hexo-convertor, which is available on <a href="https://github.com/optinsoft/wp-hexo-convertor">GitHub</a>.</p><p>Prior to migration, the WordPress blog was converted to a static version. The wp-hexo-convertor utility was then used to generate posts and redirect pages for Hexo. These redirects are essential to prevent the loss of organic traffic from Google search.</p><p>The redirects are implemented via the hexo-generator-alias plugin. I created a GitHub <a href="https://github.com/optinsoft/hexo-generator-alias">fork</a> that uses the <a href="https://hexo.io/docs/helpers#url-for">url_for</a> function instead of <a href="https://hexo.io/docs/helpers#full-url-for">full_url_for</a>.</p>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;p&gt;This blog has been migrated from WordPress to Hexo.&lt;/p&gt;
&lt;p&gt;For the blog migration, I wrote a powershell script called wp-hexo-convertor,</summary>
        
      
    
    
    
    <category term="Blog" scheme="https://optinsoft.net/blog/categories/Blog/"/>
    
    
    <category term="Hexo" scheme="https://optinsoft.net/blog/tags/Hexo/"/>
    
    <category term="powershell" scheme="https://optinsoft.net/blog/tags/powershell/"/>
    
  </entry>
  
  <entry>
    <title>IP List Generator 2.11</title>
    <link href="https://optinsoft.net/blog/2020/03/20/p=658/"/>
    <id>https://optinsoft.net/blog/2020/03/20/p=658/</id>
    <published>2020-03-19T19:00:00.000Z</published>
    <updated>2025-09-21T13:29:47.562Z</updated>
    
    <content type="html"><![CDATA[<p><em>by Vitaly, Friday, March 20th, 2020</em></p><p>Version 2.11 of the <a href="/ipgen2/">IP List Generator</a> has been released.</p><h3 id="What’s-New"><a href="#What’s-New" class="headerlink" title="What’s New"></a>What’s New</h3><p>New feature: find ISO country code for the country associated with the IP address.</p><p>IP List Generator uses MaxMind’s GeoIP2 binary database (MMDB) to resolve country by IP.</p><p><a href="/wpc/">Web Proxy Checker</a> also uses this database to find the country of the proxy by its IP.</p><p><a href="/blog/wp-content/uploads/2020/03/ipgen-2.11.png"><img src="/blog/wp-content/uploads/2020/03/ipgen-2.11-tn.png"></a></p>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;p&gt;&lt;em&gt;by Vitaly, Friday, March 20th, 2020&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Version 2.11 of the &lt;a href=&quot;/ipgen2/&quot;&gt;IP List Generator&lt;/a&gt; has been</summary>
        
      
    
    
    
    <category term="General" scheme="https://optinsoft.net/blog/categories/General/"/>
    
    <category term="IP List Generator" scheme="https://optinsoft.net/blog/categories/IP-List-Generator/"/>
    
    
  </entry>
  
  <entry>
    <title>HASH List Generator</title>
    <link href="https://optinsoft.net/blog/2020/03/19/p=640/"/>
    <id>https://optinsoft.net/blog/2020/03/19/p=640/</id>
    <published>2020-03-18T19:00:00.000Z</published>
    <updated>2025-09-21T13:29:47.111Z</updated>
    
    <content type="html"><![CDATA[<p><em>by Vitaly, Thursday, March 19th, 2020</em></p><p><a href="/md5gen/">MD5 List Generator</a> has been renamed to <a href="/md5gen/">HASH List Generator</a>.</p><p>What’s new: calculating SHA1, SHA-256, SHA-384 and SHA-512 hash values.</p><p><a href="/blog/wp-content/uploads/2020/03/hash-list-generator-2.7.png"><img src="/blog/wp-content/uploads/2020/03/hash-list-generator-2.7-tn.png"></a></p>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;p&gt;&lt;em&gt;by Vitaly, Thursday, March 19th, 2020&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/md5gen/&quot;&gt;MD5 List Generator&lt;/a&gt; has been renamed to &lt;a</summary>
        
      
    
    
    
    <category term="MD5 List Generator" scheme="https://optinsoft.net/blog/categories/MD5-List-Generator/"/>
    
    
  </entry>
  
  <entry>
    <title>Opt-In List Manager 1.6.105</title>
    <link href="https://optinsoft.net/blog/2020/03/19/p=648/"/>
    <id>https://optinsoft.net/blog/2020/03/19/p=648/</id>
    <published>2020-03-18T19:00:00.000Z</published>
    <updated>2025-09-21T13:29:47.272Z</updated>
    
    <content type="html"><![CDATA[<p><em>by Vitaly, Thursday, March 19th, 2020</em></p><p>Version 1.6.105 of the <a href="/listmanager/">Opt-In List Manager</a> has been released.</p><h3 id="What’s-New"><a href="#What’s-New" class="headerlink" title="What’s New"></a>What’s New</h3><h4 id="Extract-And-Clean"><a href="#Extract-And-Clean" class="headerlink" title="Extract And Clean"></a>Extract And Clean</h4><ol><li>Clean Mail Lists: Remove empty fields (columns).</li><li>Clean Mail Lists: Custom field (column) delimiters.</li><li>Clean Mail Lists: The number of output columns. If the source row contains less than the specified number of columns, the list manager will add missing columns (blank). If the source row contains more than the specified number of columns, the list manager will cut extra columns.</li></ol><p><a href="/blog/wp-content/uploads/2020/03/oilm-1.6-extract-and-clean.png"><img src="/blog/wp-content/uploads/2020/03/oilm-1.6-extract-and-clean-tn.png"></a></p><h4 id="Merge-E-Mail-Lists"><a href="#Merge-E-Mail-Lists" class="headerlink" title="Merge E-Mail Lists"></a>Merge E-Mail Lists</h4><ol><li>Keep Email Duplicates (remove full duplicates only).</li></ol><p><a href="/blog/wp-content/uploads/2020/03/oilm-1.6-merge.png"><img src="/blog/wp-content/uploads/2020/03/oilm-1.6-merge-tn.png"></a></p><h4 id="Misc-Utilites"><a href="#Misc-Utilites" class="headerlink" title="Misc. Utilites"></a>Misc. Utilites</h4><ol><li>Replace blanks with the specified text.</li><li>Replace the matched regular expression pattern with the specified text.</li><li>You can specify field (column) numbers to modify (add prefix, suffix or replace the text).</li><li>Calculate SHA1, SHA-256 and SHA-512 hash values.</li></ol><p><a href="/blog/wp-content/uploads/2020/03/oilm-1.6-misc.png"><img src="/blog/wp-content/uploads/2020/03/oilm-1.6-misc-tn.png"></a></p>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;p&gt;&lt;em&gt;by Vitaly, Thursday, March 19th, 2020&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Version 1.6.105 of the &lt;a href=&quot;/listmanager/&quot;&gt;Opt-In List Manager&lt;/a&gt; has been</summary>
        
      
    
    
    
    <category term="Opt-In List Manager" scheme="https://optinsoft.net/blog/categories/Opt-In-List-Manager/"/>
    
    
  </entry>
  
  <entry>
    <title>Verify Emails (Account Verifier)</title>
    <link href="https://optinsoft.net/blog/2020/03/19/p=65/"/>
    <id>https://optinsoft.net/blog/2020/03/19/p=65/</id>
    <published>2020-03-18T19:00:00.000Z</published>
    <updated>2025-09-21T13:29:47.418Z</updated>
    
    <content type="html"><![CDATA[<p><em>by Vitaly, Wednesday, May 6th, 2015</em></p><p><a href="/av/">Account Verifier</a> allows to check the validity of email addresses.</p><ol><li>Select <em>Protocol</em>: SMTP.</li><li>Check “<em>Extract Servers from accounts</em>“ box.</li><li>Check “<em>MX Lookup</em>“ box.</li><li>Select <em>Check For</em>: RCPT TO.</li></ol>]]></content>
    
    
      
      
        
        
    <summary type="html">&lt;p&gt;&lt;em&gt;by Vitaly, Wednesday, May 6th, 2015&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/av/&quot;&gt;Account Verifier&lt;/a&gt; allows to check the validity of email</summary>
        
      
    
    
    
    <category term="Account Verifier" scheme="https://optinsoft.net/blog/categories/Account-Verifier/"/>
    
    
  </entry>
  
</feed>
