<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Lucas Smith</title>
    <description>The latest articles on Forem by Lucas Smith (@lxunos).</description>
    <link>https://forem.com/lxunos</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F263799%2F532e34aa-3f6c-4520-ab33-c449a05da3ee.png</url>
      <title>Forem: Lucas Smith</title>
      <link>https://forem.com/lxunos</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/lxunos"/>
    <language>en</language>
    <item>
      <title>Vanity Post, the fun way to spread vanity</title>
      <dc:creator>Lucas Smith</dc:creator>
      <pubDate>Mon, 19 Sep 2022 10:56:48 +0000</pubDate>
      <link>https://forem.com/lxunos/vanity-post-the-fun-way-to-spread-vanity-1jhd</link>
      <guid>https://forem.com/lxunos/vanity-post-the-fun-way-to-spread-vanity-1jhd</guid>
      <description>&lt;p&gt;So over the past fortnight we built &lt;a href="https://vanitypo.st"&gt;Vanity Post&lt;/a&gt;, a fun little website that lets you create stylish images and videos of your upcoming or past posts. &lt;/p&gt;

&lt;p&gt;You can either draft a new post on the homepage or convert a tweet to a post using the &lt;a href="https://vanitypo.st/tweet/1568538724480450560"&gt;https://vanitypo.st/tweet/[tweetId]&lt;/a&gt; route.&lt;/p&gt;

&lt;p&gt;The site was built with React and Next.js and is hosted on Vercel. We use browserless.io for OpenGraph images that are stored on S3.&lt;/p&gt;

&lt;p&gt;We had a lot of fun with this one, originally mocking LinkedIn guru's who make similar styled posts before realising that the video aspect makes for engaging and more human content.&lt;/p&gt;

&lt;p&gt;We're currently live on &lt;a href="https://www.producthunt.com/posts/vanity-post"&gt;Product Hunt&lt;/a&gt; as well so if you enjoyed the tool, please spread some support over there too!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Q9yhyNEB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bwggau9igclz4aq4wkwy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q9yhyNEB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bwggau9igclz4aq4wkwy.png" alt="Vanity Post" width="800" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>webdev</category>
      <category>react</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Deobfuscating SWF files for fun and for nostalgia</title>
      <dc:creator>Lucas Smith</dc:creator>
      <pubDate>Wed, 17 Aug 2022 11:22:35 +0000</pubDate>
      <link>https://forem.com/lxunos/deobfuscating-swf-files-for-fun-and-for-nostalgia-370n</link>
      <guid>https://forem.com/lxunos/deobfuscating-swf-files-for-fun-and-for-nostalgia-370n</guid>
      <description>&lt;p&gt;If you were on the internet anytime in the 2000's or 2010's then you would know about &lt;a href="https://en.wikipedia.org/wiki/Adobe_Flash_Player"&gt;Adobe Flash Player&lt;/a&gt; (formerly &lt;a href="https://en.wikipedia.org/wiki/Macromedia"&gt;Macromedia&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;I personally would spend hours upon hours on Kongregate, New Grounds, and Miniclip playing games like Line Rider, Fancy Pants Adventure, and more.&lt;/p&gt;

&lt;p&gt;Adobe Flash brought life to the internet in the form of games, movies and other interactive content that was thought to be impossible to implement with Javascript. It provided a fully fledged environment for the development of Flash projects that was simple to use even for the less technically minded. As a result, Adobe Flash Player was one of the first things you would download after installing your web browser.&lt;/p&gt;

&lt;p&gt;Adobe Flash was a popular choice outside of the interactivity aspect as the resulting SWF file from a Flash project were much smaller than one could achieve otherwise with assets and code being compressed with either &lt;a href="https://en.wikipedia.org/wiki/Zlib"&gt;ZLIB&lt;/a&gt; or &lt;a href="https://en.wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Markov_chain_algorithm"&gt;LZMA&lt;/a&gt; compression being utilised by the resulting file itself.&lt;/p&gt;

&lt;p&gt;Another reason for the popularity of Flash was having the ability to obfuscate and site-lock your SWF file using tools such as &lt;a href="https://www.kindi.com/"&gt;SecureSWF&lt;/a&gt;, deterring people from ripping or copying your content. This was particularly enticing for content creators and game developers as it helped provide an extra layer of security for their works.&lt;/p&gt;

&lt;p&gt;Many years later and now Flash is a relic of the internet, with support ended by Adobe and browsers no longer allowing it to run. Attempts to keep content written for Flash Player alive are being made by &lt;a href="https://ruffle.rs/"&gt;Ruffle&lt;/a&gt; with support continuing to get better with every new release.&lt;/p&gt;

&lt;p&gt;On the other end of the spectrum, there is also &lt;a href="https://haxe.org/"&gt;Haxe&lt;/a&gt; which instead provides a language and syntax similar to ActionScript (which is used in Flash files) that can target a multitude of platforms with one codebase. Haxe also has tools to help convert ActionScript codebases to Haxe which has been met with moderate success.&lt;/p&gt;

&lt;h3&gt;
  
  
  That's enough history lets move onto the fun stuff
&lt;/h3&gt;

&lt;p&gt;One of my favourite things to do on the internet back in the late 2000's and early 2010's was hang out on &lt;a href="https://habbo.com"&gt;Habbo Hotel&lt;/a&gt;, it boasted a lively community and a fun pixel art playground with games, gambling, and other activities.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PduU1U6i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pdzz66k81l11t4zao79c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PduU1U6i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pdzz66k81l11t4zao79c.png" alt="Snowy Habbo Hotel" width="800" height="631"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The hotel was a fun place to hang out and play games with friends.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Habbo Hotel also used to have an active private server scene with developers working on server implementations for the Habbo Hotel client to point to. The development of these private servers was quite a feat as Habbo had utilised the obfuscation and site-locking techniques above to make modification of their client extremely difficult.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--488m5alx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i69kpaznel6qh1srarbx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--488m5alx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i69kpaznel6qh1srarbx.png" alt="JPEXS obfuscated source" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This isn't really workable nor understandable but what's that in the right-most editor?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Fortunately, from 2009 to late 2011 a misconfiguration of sorts meant that the tool that was being used for obfuscation of the client still left behind some valuable metadata that could be used to reverse the obfuscated source code to an almost original state. This went under the radar in the private server community and traditional deobfuscators back then and even today don't appear to use this metadata for any form of deobfuscation.&lt;/p&gt;

&lt;p&gt;For those who haven't worked with Flash before, in a Flash project you will typically write the logic for your game, or movie using ActionScript. ActionScript is similar to Javascript in terms of syntax with the language itself being based on the &lt;a href="https://en.wikipedia.org/wiki/ECMAScript#4th_Edition_(abandoned)"&gt;abandoned ECMAScript 4 specification&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;ActionScript is then compiled into bytecode which is interpreted by the ActionScript Virtual Machine (AVM) which is embedded in the Adobe Flash Player plugin. Because ActionScript is compiled into bytecode, tools like SecureSWF can then read and modify that bytecode to be unintelligible to humans but still valid for the underlying VM, this modification comes at a slight performance cost but provides a massive net gain in securing private codebases.&lt;/p&gt;

&lt;p&gt;We can use disassemblers such as &lt;a href="https://github.com/CyberShadow/RABCDAsm"&gt;RABCDasm&lt;/a&gt; to disassemble an SWF file into a set of semi-readable assembly files. Where possible we may also use tools such as &lt;a href="https://github.com/jindrapetrik/jpexs-decompiler"&gt;JPEXS&lt;/a&gt; to convert said assembly into legible ActionScript code.&lt;/p&gt;

&lt;p&gt;So when working with the Habbo Hotel client, we can see the code is almost intelligible with most identifiers being completely mangled to the point of no longer being valid ActionScript.&lt;/p&gt;

&lt;p&gt;The automatic deobfuscation tools provided with JPEXS also don't assist as they simply rename all these identifiers to things like &lt;code&gt;variable1, variable2, variable3&lt;/code&gt; and so forth, that said, when we look at the PCODE in JPEXS we can catch glimpses of the correct identifiers for the given classes, methods and more.&lt;/p&gt;

&lt;p&gt;Armed with this knowledge we can disassemble our SWF file using RABCDAsm and start playing with the provided assembly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;→ tree | head -500

├── Habbo-0
│   ├── _-3LN.class.asasm
│   ├── _-3LN.script.asasm
│   ├── com
│   │   └── sulake
│   │       └── core
│   │           └── runtime
│   │               ├── _-0sH.class.asasm
│   │               └── _-0sH.script.asasm
│   ├── Habbo-0.main.asasm
│   ├── Habbo.class.asasm
│   ├── Habbo.script.asasm
│   ├── Logger.class.asasm
│   ├── Logger.script.asasm
├── Habbo-0.abc
├── Habbo-1
│   ├── _-00.class.asasm
│   ├── _-00i.class.asasm
│   ├── _-00i.script.asasm
│   ├── _-00k.class.asasm
│   ├── _-00K_.class.asasm
│   ├── _-00k.script.asasm
│   ├── _-00K_.script.asasm

...[SNIP]...

│   ├── _-zf
│   │   ├── _-1b9.class.asasm
│   │   ├── _-1b9.script.asasm
│   │   ├── _-1Uq.class.asasm
│   │   ├── _-1Uq.script.asasm
│   │   ├── _-Cd.class.asasm
│   │   ├── _-Cd.script.asasm
│   │   ├── _-Oa.class.asasm
│   │   └── _-Oa.script.asasm
│   ├── _-Zh.class.asasm
│   ├── _-Zh.script.asasm
│   ├── _-ZM.class.asasm
│   ├── _-ZM.script.asasm
│   ├── _-Zr.class.asasm
│   ├── _-Zr.script.asasm
│   ├── _-Zu.class.asasm
│   ├── _-Zu.script.asasm
│   ├── _-ZV.class.asasm
│   └── _-ZV.script.asasm
├── Habbo-1.abc
└── Habbo.swf

540 directories, 7522 files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The sheer amount of files can be quite intimidating&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class
 refid "_-03c:_-1W9"
 instance QName(PackageNamespace("_-03c"), "_-1W9")
  extends QName(PackageNamespace("_-03c"), "_-04U")
  flag SEALED
  flag PROTECTEDNS
  protectedns ProtectedNamespace("_-6L")
  iinit
   name "com.sulake.habbo.ui.widget.messages:RoomWidgetPetCommandMessage/RoomWidgetPetCommandMessage"
   refid "_-03c:_-1W9/instance/init"
   param QName(PackageNamespace(""), "String")
   param QName(PackageNamespace(""), "int")
   param QName(PackageNamespace(""), "String")
   flag HAS_OPTIONAL
   optional Null()
   body
    maxstack 2
    localcount 4
    initscopedepth 5
    maxscopedepth 6
    code
     getlocal0
     pushscope

     getlocal0
     jump                L10

     ; 0xB0
     ; 0xC1
     ; 0x96
     ; 0x57
     ; 0x28
     ; 0x1E
L10:
     getlocal1
     constructsuper      1

     getlocal0
     getlocal2
     initproperty        QName(PrivateNamespace("_-6L"), "_-0VE")

     getlocal0
     getlocal3
     initproperty        QName(PrivateNamespace("_-6L"), "_-3Ao")

     returnvoid
    end ; code
   end ; body
  end ; method
  trait slot QName(PrivateNamespace("_-6L"), "_-0VE") type QName(PackageNamespace(""), "int") value Integer(0) end
  trait slot QName(PrivateNamespace("_-6L"), "_-3Ao") type QName(PackageNamespace(""), "String") end
  trait getter QName(PackageNamespace(""), "_-JP")
   method
    name "com.sulake.habbo.ui.widget.messages:RoomWidgetPetCommandMessage/petId/get"
    refid "_-03c:_-1W9/instance/_-JP/getter"
    returns QName(PackageNamespace(""), "int")
    body
     maxstack 1
     localcount 1
     initscopedepth 5
     maxscopedepth 6
     code
      getlocal0
      pushscope

      getlocal0
      getproperty         QName(PrivateNamespace("_-6L"), "_-0VE")
      returnvalue
     end ; code
    end ; body
   end ; method
  end ; trait
  trait getter QName(PackageNamespace(""), "value")
   method
    name "com.sulake.habbo.ui.widget.messages:RoomWidgetPetCommandMessage/value/get"
    refid "_-03c:_-1W9/instance/value/getter"
    returns QName(PackageNamespace(""), "String")
    body
     maxstack 1
     localcount 1
     initscopedepth 5
     maxscopedepth 6
     code
      getlocal0
      pushscope

      getlocal0
      getproperty         QName(PrivateNamespace("_-6L"), "_-3Ao")
      returnvalue
     end ; code
    end ; body
   end ; method
  end ; trait
 end ; instance
 cinit
  refid "_-03c:_-1W9/class/init"
  body
   maxstack 2
   localcount 1
   initscopedepth 4
   maxscopedepth 5
   code
    getlocal0
    pushscope

    findproperty        QName(PackageNamespace(""), "_-1pG")
    jump                L10

    ; 0xB0
    ; 0xD4
    ; 0xC5
    ; 0x23
    ; 0xA7
    ; 0x2B
L10:
    pushstring          "RWPCM_REQUEST_PET_COMMANDS"
    initproperty        QName(PackageNamespace(""), "_-1pG")

    findproperty        QName(PackageNamespace(""), "_-3K8")
    pushstring          "RWPCM_PET_COMMAND"
    initproperty        QName(PackageNamespace(""), "_-3K8")

    returnvoid
   end ; code
  end ; body
 end ; method
 trait const QName(PackageNamespace(""), "_-1pG") slotid 1 type QName(PackageNamespace(""), "String") value Utf8("RWPCM_REQUEST_PET_COMMANDS") end
 trait const QName(PackageNamespace(""), "_-3K8") slotid 2 type QName(PackageNamespace(""), "String") value Utf8("RWPCM_PET_COMMAND") end
end ; class

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;We're starting to see some patterns with identifiers here&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While poking around, you may notice that the original identifiers are still within the file under what can only be described as some metadata fields within the assembly. It appears as though SecureSWF won't mangle everything by default unless you tell it to.&lt;/p&gt;

&lt;p&gt;The fact that these metadata fields are called things like &lt;code&gt;name&lt;/code&gt; is humorous and makes our job all the more easier.&lt;/p&gt;

&lt;p&gt;Using this, we can begin to write a Python script to read these assembly files and build a dictionary of identifiers based on these metadata fields.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="s"&gt;"""
Gets the namespace and classname for the package where available
defaulting to an empty string.

This will typically contain the string from `name` field in the
"iinit" section of the assembly file.

:Example:

&amp;gt;&amp;gt; get_namespace_and_classname("com.sulake.habbo.ui.widget.furniture.ecotronbox:EcotronBoxFurniWidget/EcotronBoxFurniWidget")
&amp;gt;&amp;gt; get_namespace_and_classname("Habbo_habboLogoClass/Habbo_habboLogoClass")

("com.sulake.habbo.ui.widget.furniture.ecotronbox", "EcotronBoxFurniWidget")
("", "Habbo_habboLogoClass")
"""&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_namespace_and_classname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;semicolon_splot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;semicolon_splot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;classname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;classname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;semicolon_splot&lt;/span&gt;

        &lt;span class="n"&gt;classname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;classname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="s"&gt;"""
Gets the name of a given getter or setter where available
returning None if it can't be determined.

This will typically contain the string from "name" field in the
"trait getter" or "trait setter" section of the assembly file.

:Example:

&amp;gt;&amp;gt; get_getter_or_setter_name("_-xV9/get")
&amp;gt;&amp;gt; get_getter_or_setter_name("com.sulake.habbo.catalog.viewer:ProductContainer/firstProduct/get")
&amp;gt;&amp;gt; get_getter_or_setter_name("com.sulake.habbo.catalog.recycler:RecyclerLogic/private:statusActive/get")
&amp;gt;&amp;gt; get_getter_or_setter_name("com.sulake.habbo.ui.widget.memenu:IWidgetAvatarEffect/com.sulake.habbo.ui.widget.memenu:IWidgetAvatarEffect:isInUse/get")

None
"firstProduct"
"statusActive"
"isInUse"
"""&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_getter_or_setter_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Union&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;name_splot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# If there aren't 3 "/" characters, we're dealing with
&lt;/span&gt;    &lt;span class="c1"&gt;# something that we typically can't handle so lets return
&lt;/span&gt;    &lt;span class="c1"&gt;# early.
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name_splot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="c1"&gt;# The final part of the name will be either "get" or "set"
&lt;/span&gt;    &lt;span class="c1"&gt;# with the real method name being just before that.
&lt;/span&gt;    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name_splot&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# Sometimes the package or other garbage will be included
&lt;/span&gt;    &lt;span class="c1"&gt;# in the name section, if it appears we can skip over it
&lt;/span&gt;    &lt;span class="c1"&gt;# by splitting on ":" and getting the last part which will be
&lt;/span&gt;    &lt;span class="c1"&gt;# the name.
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s"&gt;":"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can continue iterating on the above, adding more methods for constants, methods, and variables while noting any other patterns we see in the assembly until we have a moderately robust reader and dictionary builder.&lt;/p&gt;

&lt;p&gt;Once we've built our dictionary of replacements, we can once again iterate over the assembly files and replace the obfuscated &lt;code&gt;_-&lt;/code&gt; identifiers with the ones we've found in the dictionary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="s"&gt;"""
Given a file path, open the file and replace any identifiers found in the dictionary with
their deobfuscated counterparts.
"""&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;replace_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;replacements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"r+"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;content_lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readlines&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;new_lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content_lines&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"#include"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"pushstring"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
            &lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;replacements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
                    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                        &lt;span class="c1"&gt;# This handy little regex will ensure we're only working within
&lt;/span&gt;                        &lt;span class="c1"&gt;# quoted content so we don't accidentally disturb anything else
&lt;/span&gt;                        &lt;span class="c1"&gt;# in the assembly file.
&lt;/span&gt;                        &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                            &lt;span class="sa"&gt;rf&lt;/span&gt;&lt;span class="s"&gt;"(^|[\"\/:])&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;([\"\/:]|$)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;rf&lt;/span&gt;&lt;span class="s"&gt;"\1&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;\2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;
                        &lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="n"&gt;new_lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Reset the file to the beginning and truncate the content
&lt;/span&gt;        &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;seek&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;truncate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c1"&gt;# Then write the new contents to the file
&lt;/span&gt;        &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writelines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="s"&gt;"""
When ran as a script, gather a list of paths for files we want to
process and then build the replacement dictionary using our heuristics.

Once complete begin replacing the file contents utilising a worker per
thread to speed up the process.
"""&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;paths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Habbo-*/**/*.class.asasm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;recursive&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;replacements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;build_replacements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cpu_count&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;fn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;partial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;replace_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;replacements&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;replacements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;imap_unordered&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;all_paths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"Processed &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; files"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"__main__"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can use RABCDasm once more to assemble the modified files into an SWF which we will then open in JPEXS to see the updated ActionScript.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WxdlFgWg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1ovofq26dsaqoyqseyiz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WxdlFgWg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1ovofq26dsaqoyqseyiz.png" alt="JPEXS deobfuscated source" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And with that we've now deobfuscated an SWF that left behind enough meaningful metadata.&lt;/p&gt;

&lt;h3&gt;
  
  
  So what about files that don't leave behind enough metadata?
&lt;/h3&gt;

&lt;p&gt;Unfortunately, for files that don't leave behind enough meaningful metadata we can't do much other than attempt to interpret the assembly file or obfuscated ActionScript. We may be able to restore some minor items where metadata was left in &lt;code&gt;QName&lt;/code&gt; and &lt;code&gt;Namespace&lt;/code&gt; fields, but outside of that there isn't much to be done.&lt;/p&gt;

&lt;p&gt;For this reason, things such as the Habbo Clients from 2012 onwards are not reversible. In the event that you have a set of reversed files from earlier versions, you may be able to build some form of static analysis tool to partially reverse the file with knowledge of its prior state.&lt;/p&gt;

&lt;h3&gt;
  
  
  So what can we now do with the SWF we've deobfuscated?
&lt;/h3&gt;

&lt;p&gt;While Flash might be dead, you can still play Flash content using Ruffle or older builds of &lt;a href="https://www.electronjs.org/"&gt;Electron&lt;/a&gt; and &lt;a href="https://archive.org/search.php?query=subject%3A%22pepper%20flash%22"&gt;Pepper Flash Plugin&lt;/a&gt;. Alternatively, you might attempt to translate the source code into Haxe so you can compile it into a universal application for both web, mobile and desktop. You might even use the source to attempt a rewrite as a JavaScript application using &lt;a href="https://pixijs.com/"&gt;PixiJS&lt;/a&gt; or similar.&lt;/p&gt;

</description>
      <category>devjournal</category>
      <category>security</category>
      <category>programming</category>
    </item>
    <item>
      <title>Creating a Next-like layout system in Vue</title>
      <dc:creator>Lucas Smith</dc:creator>
      <pubDate>Sat, 13 Aug 2022 13:02:10 +0000</pubDate>
      <link>https://forem.com/lxunos/creating-a-next-like-layout-system-in-vue-3iib</link>
      <guid>https://forem.com/lxunos/creating-a-next-like-layout-system-in-vue-3iib</guid>
      <description>&lt;p&gt;While learning Next and React, I had really come to like the straightforward way that layouts were able to be added to the routing system.&lt;/p&gt;

&lt;p&gt;Instead of having the framework take care of layouts automagically, Next lets the reader &lt;a href="https://nextjs.org/docs/basic-features/layouts" rel="noopener noreferrer"&gt;perform the implementation&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Said implementation looks similar to the below example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * layouts/default.js
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;DefaultLayout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;My&lt;/span&gt; &lt;span class="nx"&gt;Website&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/header&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/main&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;footer&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;Copywrite&lt;/span&gt; &lt;span class="mi"&gt;2022&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;My&lt;/span&gt; &lt;span class="nx"&gt;Website&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/footer&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * pages/index.js
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;This&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;my&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getLayout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DefaultLayout&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/DefaultLayout&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
&lt;span class="cm"&gt;/**
 * pages/_app.js
 */&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MyApp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pageProps&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Use the layout defined at the page level, if available&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getLayout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getLayout&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;getLayout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;pageProps&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;)
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now while there is currently an &lt;a href="https://nextjs.org/blog/layouts-rfc" rel="noopener noreferrer"&gt;RFC&lt;/a&gt; to improve the layouts situation in Next, the above is suitable for most basic sites with issues only arising as you need to track more and more state within your layouts.&lt;/p&gt;

&lt;p&gt;So when using Vue we don't particularly have a layout system either unless you're using something like &lt;a href="https://nuxtjs.org/" rel="noopener noreferrer"&gt;Nuxt&lt;/a&gt; or &lt;a href="https://github.com/JohnCampionJr/vite-plugin-vue-layouts" rel="noopener noreferrer"&gt;Vite Plugin Vue Layouts&lt;/a&gt; both of which abstract the problem away with some magic. Unfortunately, Nuxt doesn't have fantastic JSX/TSX support with Nuxt3 as of yet and the Vite Plugin is currently only designed to handle Single File Components (SFCs), so for a JSX/TSX user such as myself this is untenable.&lt;/p&gt;

&lt;p&gt;To solve this issue we can take the proposed solution from Next and make it compatible with Vue, to do so we need to utilise the scoped slots available within the &lt;code&gt;&amp;lt;RouterView /&amp;gt;&lt;/code&gt; component so we can check for a &lt;code&gt;getLayout&lt;/code&gt; method defined on the page.&lt;/p&gt;

&lt;p&gt;For the purposes of this article, we will assume that you are using JSX with Vue, although this is far from the norm it is my preference. If you find yourself using SFCs still, don't fear you can also still benefit from the code in this article which can be seen demonstrated at the &lt;a href="https://github.com/Mythie/vue-next-like-layouts/" rel="noopener noreferrer"&gt;example repository for this article&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  So why do we need layouts anyway?
&lt;/h3&gt;

&lt;p&gt;Using layouts while working with libraries such as React or Vue allow us to significantly reduce the amount that is occurring on a single page. We can extract simple logic and elements to the layout in addition to preparing stores or other providers for child component consumption.&lt;/p&gt;

&lt;p&gt;This also allows us to maintain consistency over a set of pages that we have deemed to be related by ensuring that if we were to update the overall container for the pages, they would all then receive the update rather than potentially becoming inconsistent.&lt;/p&gt;

&lt;h3&gt;
  
  
  So why not just define the layout within the render function or template?
&lt;/h3&gt;

&lt;p&gt;While we could wrap our render function or template with the layout, it is typically not preferred as it shows a tight level of coupling between the two and adds additional cognitive load to editors as they must discard the first element within a given render function or template.&lt;/p&gt;

&lt;p&gt;Due to this we have seen a standardisation around layouts being defined as either a property or method on a component and or route.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvv3e79nf4xjtsuavd0kk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvv3e79nf4xjtsuavd0kk.png" alt="Layout Styles"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Well then how do we add this layout system?
&lt;/h3&gt;

&lt;p&gt;So to start, in the land of Vue we use &lt;a href="https://router.vuejs.org/" rel="noopener noreferrer"&gt;Vue Router&lt;/a&gt; for routing. It is a first party plugin and solves all your routing needs, providing both Web History and Hash based routing. Additionally, it supports nested routes and router views.&lt;/p&gt;

&lt;p&gt;Traditionally we would simply add a &lt;code&gt;&amp;lt;RouterView /&amp;gt;&lt;/code&gt; component anywhere where we wanted to render a page and Vue Router would go and find the corresponding component and then render it for us. &lt;/p&gt;

&lt;p&gt;However, Vue Router also allows us as the user to render our own content using &lt;a href="https://vuejs.org/guide/components/slots.html" rel="noopener noreferrer"&gt;slots&lt;/a&gt; where it'll pass the &lt;code&gt;Component&lt;/code&gt; and &lt;code&gt;route&lt;/code&gt; as a set of props to our slot content. &lt;/p&gt;

&lt;p&gt;We can utilise this secondary method of rendering to instead check if a component has a &lt;code&gt;getLayout&lt;/code&gt; method and then render it with the page component as an argument. &lt;/p&gt;

&lt;p&gt;This will look like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineComponent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="nf"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;attrs&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RouterView&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{{&lt;/span&gt;
          &lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;// If the component comes with a layout then we should render that with the component&lt;/span&gt;
            &lt;span class="c1"&gt;// as a child&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;getLayout&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getLayout&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLayout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;h&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;attrs&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c1"&gt;// Otherwise we default to the typical &amp;lt;RouterView /&amp;gt; behaviour&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;h&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;attrs&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;}}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/RouterView&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the signature for &lt;code&gt;getLayout&lt;/code&gt; being the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;getLayout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;VNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;VNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To keep this tidy, we recommend extracting the logic in the &lt;code&gt;&amp;lt;App /&amp;gt;&lt;/code&gt; component into a &lt;code&gt;&amp;lt;RouterViewWithLayout /&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;AppView /&amp;gt;&lt;/code&gt; component instead. This will also come in handy when dealing with nested &lt;code&gt;&amp;lt;RouterView /&amp;gt;&lt;/code&gt; components if you opt to use them in your project.&lt;/p&gt;

&lt;h3&gt;
  
  
  So now what?
&lt;/h3&gt;

&lt;p&gt;Now that we have the logic for rendering a layout when supplied via &lt;code&gt;getLayout&lt;/code&gt; we can use it in our pages. You can see this in action in the &lt;a href="https://stackblitz.com/" rel="noopener noreferrer"&gt;Stackblitz Playground&lt;/a&gt; below.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/github-6bpfoe?ctl=1&amp;amp;embed=1&amp;amp;file=src/App.tsx" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Bonus Round: SFC Layouts
&lt;/h3&gt;

&lt;p&gt;For SFCs we use a &lt;code&gt;layout&lt;/code&gt; property which references a component rather than a &lt;code&gt;getLayout&lt;/code&gt; method that returns &lt;code&gt;VNodes&lt;/code&gt;. This is due to the limitations in where one can use &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; syntax. This means that while the above will still work fantastically for most needs, it still won't be as flexible as the JSX variant.&lt;/p&gt;

&lt;p&gt;You can see the SFC version in use at the alternative playground below. &lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/github-omgktb?ctl=1&amp;amp;embed=1&amp;amp;file=src/AppView.vue" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>vue</category>
    </item>
  </channel>
</rss>
