Compare commits

..

14 Commits

25 changed files with 442 additions and 447 deletions

View File

@@ -1,103 +0,0 @@
* {
box-sizing: border-box;
}
/* Looks bad. And it is! Workaround for having no control over
* how the markdown python module renders the post.
*/
.post > article > p > img {
/* Prevent images in blog posts from getting too big */
max-width: 800px;
}
.profile-picture {
max-width: 200px;
}
h1, h2, h3, h4 {
color: #9b59b6;
}
.post-list {
padding: 10px;
}
.post-list-item {
display: block;
max-width: 800px;
}
.post-list-item-title {
color: #3498db;
}
.post {
display: block;
width: 100%;
padding: 10px;
font-size: 21px;
}
.text {
font-size: 21px;
}
.text-content {
max-width: 1000px;
}
.stretch-horizontally {
width: 100%;
}
@media only screen and (max-width: 768px) {
.page-title {
/* The page header title otherwise overflows the page on small screens */
font-size: 8vw;
}
.text-content {
/* Otherwise the page content overflows the page */
max-width: 100%;
}
.text {
/* A smaller font looks better on smaller devices */
font-size: 19px;
}
.post {
/* A smaller font looks better on smaller devices */
font-size: 19px;
/* Otherwise the entire page overflows for some reason */
width: 100%;
}
p > img {
/* This should match all images used inside blog posts */
width: 100%;
}
}
code {
display: inline-block;
padding: 0 3px;
border-radius: 3px;
background-color: black;
line-height: 1.5;
}
pre > code {
background-color: black;
line-height: 1.5;
border-radius: 3px;
padding: 10px;
width: 100%;
overflow-x: auto;
}

85
assets/css/code.css Normal file
View File

@@ -0,0 +1,85 @@
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
/* From https://github.com/richleland/pygments-css/blob/master/native.css */
.codehilite .hll { background-color: #404040 }
.codehilite { background: #202020; color: #d0d0d0 }
.codehilite .c { color: #999999; font-style: italic } /* Comment */
.codehilite .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.codehilite .esc { color: #d0d0d0 } /* Escape */
.codehilite .g { color: #d0d0d0 } /* Generic */
.codehilite .k { color: #6ab825; font-weight: bold } /* Keyword */
.codehilite .l { color: #d0d0d0 } /* Literal */
.codehilite .n { color: #d0d0d0 } /* Name */
.codehilite .o { color: #d0d0d0 } /* Operator */
.codehilite .x { color: #d0d0d0 } /* Other */
.codehilite .p { color: #d0d0d0 } /* Punctuation */
.codehilite .ch { color: #999999; font-style: italic } /* Comment.Hashbang */
.codehilite .cm { color: #999999; font-style: italic } /* Comment.Multiline */
.codehilite .cp { color: #cd2828; font-weight: bold } /* Comment.Preproc */
.codehilite .cpf { color: #999999; font-style: italic } /* Comment.PreprocFile */
.codehilite .c1 { color: #999999; font-style: italic } /* Comment.Single */
.codehilite .cs { color: #e50808; font-weight: bold; background-color: #520000 } /* Comment.Special */
.codehilite .gd { color: #d22323 } /* Generic.Deleted */
.codehilite .ge { color: #d0d0d0; font-style: italic } /* Generic.Emph */
.codehilite .gr { color: #d22323 } /* Generic.Error */
.codehilite .gh { color: #ffffff; font-weight: bold } /* Generic.Heading */
.codehilite .gi { color: #589819 } /* Generic.Inserted */
.codehilite .go { color: #cccccc } /* Generic.Output */
.codehilite .gp { color: #aaaaaa } /* Generic.Prompt */
.codehilite .gs { color: #d0d0d0; font-weight: bold } /* Generic.Strong */
.codehilite .gu { color: #ffffff; text-decoration: underline } /* Generic.Subheading */
.codehilite .gt { color: #d22323 } /* Generic.Traceback */
.codehilite .kc { color: #6ab825; font-weight: bold } /* Keyword.Constant */
.codehilite .kd { color: #6ab825; font-weight: bold } /* Keyword.Declaration */
.codehilite .kn { color: #6ab825; font-weight: bold } /* Keyword.Namespace */
.codehilite .kp { color: #6ab825 } /* Keyword.Pseudo */
.codehilite .kr { color: #6ab825; font-weight: bold } /* Keyword.Reserved */
.codehilite .kt { color: #6ab825; font-weight: bold } /* Keyword.Type */
.codehilite .ld { color: #d0d0d0 } /* Literal.Date */
.codehilite .m { color: #3677a9 } /* Literal.Number */
.codehilite .s { color: #ed9d13 } /* Literal.String */
.codehilite .na { color: #bbbbbb } /* Name.Attribute */
.codehilite .nb { color: #24909d } /* Name.Builtin */
.codehilite .nc { color: #447fcf; text-decoration: underline } /* Name.Class */
.codehilite .no { color: #40ffff } /* Name.Constant */
.codehilite .nd { color: #ffa500 } /* Name.Decorator */
.codehilite .ni { color: #d0d0d0 } /* Name.Entity */
.codehilite .ne { color: #bbbbbb } /* Name.Exception */
.codehilite .nf { color: #447fcf } /* Name.Function */
.codehilite .nl { color: #d0d0d0 } /* Name.Label */
.codehilite .nn { color: #447fcf; text-decoration: underline } /* Name.Namespace */
.codehilite .nx { color: #d0d0d0 } /* Name.Other */
.codehilite .py { color: #d0d0d0 } /* Name.Property */
.codehilite .nt { color: #6ab825; font-weight: bold } /* Name.Tag */
.codehilite .nv { color: #40ffff } /* Name.Variable */
.codehilite .ow { color: #6ab825; font-weight: bold } /* Operator.Word */
.codehilite .w { color: #666666 } /* Text.Whitespace */
.codehilite .mb { color: #3677a9 } /* Literal.Number.Bin */
.codehilite .mf { color: #3677a9 } /* Literal.Number.Float */
.codehilite .mh { color: #3677a9 } /* Literal.Number.Hex */
.codehilite .mi { color: #3677a9 } /* Literal.Number.Integer */
.codehilite .mo { color: #3677a9 } /* Literal.Number.Oct */
.codehilite .sa { color: #ed9d13 } /* Literal.String.Affix */
.codehilite .sb { color: #ed9d13 } /* Literal.String.Backtick */
.codehilite .sc { color: #ed9d13 } /* Literal.String.Char */
.codehilite .dl { color: #ed9d13 } /* Literal.String.Delimiter */
.codehilite .sd { color: #ed9d13 } /* Literal.String.Doc */
.codehilite .s2 { color: #ed9d13 } /* Literal.String.Double */
.codehilite .se { color: #ed9d13 } /* Literal.String.Escape */
.codehilite .sh { color: #ed9d13 } /* Literal.String.Heredoc */
.codehilite .si { color: #ed9d13 } /* Literal.String.Interpol */
.codehilite .sx { color: #ffa500 } /* Literal.String.Other */
.codehilite .sr { color: #ed9d13 } /* Literal.String.Regex */
.codehilite .s1 { color: #ed9d13 } /* Literal.String.Single */
.codehilite .ss { color: #ed9d13 } /* Literal.String.Symbol */
.codehilite .bp { color: #24909d } /* Name.Builtin.Pseudo */
.codehilite .fm { color: #447fcf } /* Name.Function.Magic */
.codehilite .vc { color: #40ffff } /* Name.Variable.Class */
.codehilite .vg { color: #40ffff } /* Name.Variable.Global */
.codehilite .vi { color: #40ffff } /* Name.Variable.Instance */
.codehilite .vm { color: #40ffff } /* Name.Variable.Magic */
.codehilite .il { color: #3677a9 } /* Literal.Number.Integer.Long */

View File

@@ -1,74 +0,0 @@
/* Generated by python pygmentize, modified by me*/
pre { line-height: 125%; }
td.linenos pre { color: #000000; background-color: #f0f0f0; padding-left: 5px; padding-right: 5px; }
span.linenos { color: #000000; background-color: #f0f0f0; padding-left: 5px; padding-right: 5px; }
td.linenos pre.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.codehilite .hll { background-color: #ffffcc }
.codehilite .c { color: #408080; font-style: italic } /* Comment */
.codehilite .err { border: 1px solid #FF0000 } /* Error */
.codehilite .k { color: #008000; font-weight: bold } /* Keyword */
.codehilite .o { color: #666666 } /* Operator */
.codehilite .ch { color: #408080; font-style: italic } /* Comment.Hashbang */
.codehilite .cm { color: #408080; font-style: italic } /* Comment.Multiline */
.codehilite .cp { color: #BC7A00 } /* Comment.Preproc */
.codehilite .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */
.codehilite .c1 { color: #408080; font-style: italic } /* Comment.Single */
.codehilite .cs { color: #408080; font-style: italic } /* Comment.Special */
.codehilite .gd { color: #A00000 } /* Generic.Deleted */
.codehilite .ge { font-style: italic } /* Generic.Emph */
.codehilite .gr { color: #FF0000 } /* Generic.Error */
.codehilite .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.codehilite .gi { color: #00A000 } /* Generic.Inserted */
.codehilite .go { color: #888888 } /* Generic.Output */
.codehilite .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
.codehilite .gs { font-weight: bold } /* Generic.Strong */
.codehilite .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.codehilite .gt { color: #0044DD } /* Generic.Traceback */
.codehilite .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
.codehilite .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
.codehilite .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
.codehilite .kp { color: #008000 } /* Keyword.Pseudo */
.codehilite .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
.codehilite .kt { color: #B00040 } /* Keyword.Type */
.codehilite .m { color: #666666 } /* Literal.Number */
.codehilite .s { color: #BA2121 } /* Literal.String */
.codehilite .na { color: #7D9029 } /* Name.Attribute */
.codehilite .nb { color: #008000 } /* Name.Builtin */
.codehilite .nc { color: #0000FF; font-weight: bold } /* Name.Class */
.codehilite .no { color: #880000 } /* Name.Constant */
.codehilite .nd { color: #AA22FF } /* Name.Decorator */
.codehilite .ni { color: #999999; font-weight: bold } /* Name.Entity */
.codehilite .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
.codehilite .nf { color: #0000FF } /* Name.Function */
.codehilite .nl { color: #A0A000 } /* Name.Label */
.codehilite .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
.codehilite .nt { color: #008000; font-weight: bold } /* Name.Tag */
.codehilite .nv { color: #7473CE } /* Name.Variable */
.codehilite .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
.codehilite .w { color: #bbbbbb } /* Text.Whitespace */
.codehilite .mb { color: #666666 } /* Literal.Number.Bin */
.codehilite .mf { color: #666666 } /* Literal.Number.Float */
.codehilite .mh { color: #666666 } /* Literal.Number.Hex */
.codehilite .mi { color: #666666 } /* Literal.Number.Integer */
.codehilite .mo { color: #666666 } /* Literal.Number.Oct */
.codehilite .sa { color: #BA2121 } /* Literal.String.Affix */
.codehilite .sb { color: #BA2121 } /* Literal.String.Backtick */
.codehilite .sc { color: #BA2121 } /* Literal.String.Char */
.codehilite .dl { color: #BA2121 } /* Literal.String.Delimiter */
.codehilite .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
.codehilite .s2 { color: #BA2121 } /* Literal.String.Double */
.codehilite .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
.codehilite .sh { color: #BA2121 } /* Literal.String.Heredoc */
.codehilite .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
.codehilite .sx { color: #008000 } /* Literal.String.Other */
.codehilite .sr { color: #BB6688 } /* Literal.String.Regex */
.codehilite .s1 { color: #BA2121 } /* Literal.String.Single */
.codehilite .ss { color: #19177C } /* Literal.String.Symbol */
.codehilite .bp { color: #008000 } /* Name.Builtin.Pseudo */
.codehilite .fm { color: #0000FF } /* Name.Function.Magic */
.codehilite .vc { color: #19177C } /* Name.Variable.Class */
.codehilite .vg { color: #19177C } /* Name.Variable.Global */
.codehilite .vi { color: #19177C } /* Name.Variable.Instance */
.codehilite .vm { color: #19177C } /* Name.Variable.Magic */
.codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */

View File

@@ -1,41 +0,0 @@
<!-- title: About "PapaTutuWawa" -->
<!-- description: -->
<!-- render: yes -->
<div class="vertical text">
<div class="horizontal-center">
<div class="text-content">
<h3>About "PapaTutuWawa"</h3>
<p>
<img
class="profile-picture"
src="assets/img/profile.jpg"
alt="Profile Picture" />
</p>
<div class="quote">
<p>
Student, Anime expert, Vocaloid listener, Docker and Linux fan
and hobby SysAdmin.
</p>
</div>
<ul>
<li><a href="https://{{ git_url }}/">Code</a></li>
<li><a href="https://{{ blog_url }}/">Blog</a></li>
<li><a href="https://{{ mastodon_url }}/">Mastodon</a></li>
</ul>
<h3>Contact</h3>
<ul>
<li>EMail: <i>{{ email_user }} ["a" with a weird circle] {{ email_domain }}</i> (<a href="https://{{ email_gpg_url}}">GPG</a>)</li>
</ul>
<h3>About This Page</h3>
<ul>
<li><a href="https://{{ git_url }}/PapaTutuWawa/blog.polynom.me">Source</a></li>
<li>Last updated <i>{{ build_time }}</i></li>
</ul>
</div>
</div>
</div>

View File

@@ -1,17 +0,0 @@
-----BEGIN PGP SIGNATURE-----
iQJMBAABCAA2FiEEvBU+39pRCqHFhwUCToYVYy9G5oAFAmGjjaYYHHBhcGF0dXR1
d2F3YUBwb2x5bm9tLm1lAAoJEE6GFWMvRuaA5/4P/1SU69isY6/kRRc2VpZ9MYni
/pCd1yNtoYYC3yuMij22k7nx1osoEGofjdNiSp15DOZI/RVhKdeppU2BxJ8LuejB
wllqjhU5sS2fa9Me0P7Sv33o9jQAUmPKVY3KmdwkNj+/Vd1gmxAYEhoU/9KhzRcF
fF1wVFTfFbtRmHan/3yQbW807W2TnkqOi1c6i6PSCgf20H5rHglOdYzKr1+suQ6T
nx1+2hYlKzPkMyU9+R21PPdU7+3lUMxuvJ301xIOGD3ri45FHKgg5rpagdJctC1w
sVccXQERn0yuU40YHyAmXFy6BOuJk+8Eh7bb/8X/ASpuIjZccyyGlja/h5w3gYYm
rni4ApdH+VtNZtSwTb4plxaktgEXiOvIvF0u7z2Xs4J4XPorvjFwq5nZU2A6MeNd
hDfdmAOOfjfafgigQRSRbx35YInw45USccE9kyib/YlBDf2snCYXgGqGiREBmehf
7tGS10NWidomhn14otlXB/H4kQ8PwjrfpwmDCXPhtCZAQ8g+YF5ynvzjcalQCxEK
D1+0ADpmX7Gbz0AXrRu2mSbYJyJD+11+35KOM6mV1BMU8f3VVRB3FIwb8/jcU4T9
V+Jcnz2KSjxKS9UXVXeGkXcYPEx3zYXwHOwlzfsLmq7wsvjZKSqqOCSicERP5KA2
yZI/9w2nH5fS9S5ZP4rw
=4/jw
-----END PGP SIGNATURE-----

View File

@@ -23,7 +23,7 @@ from the device?
### Getting Output ### Getting Output
While preparing myself for this task, I learned that there are a couple of ways. While preparing myself for this task, I learned that there are a couple of ways.
One is called [*RAM console*](https://wiki.postmarketos.org/wiki/Mainlining_FAQ#Writing_dmesg_to_RAM_and_reading_it_out_after_reboot). What is does is just dump everything that the kernel prints into a One is called [*RAM console*](https://wiki.postmarketos.org/wiki/Mainlining_FAQ#Writing_dmesg_to_RAM_and_reading_it_out_after_reboot). What it does is just dump everything that the kernel prints into a
reserved region of memory, which can later be retrieved by reading from `/proc/last_kmsg` with a reserved region of memory, which can later be retrieved by reading from `/proc/last_kmsg` with a
downstream kernel. downstream kernel.
@@ -94,7 +94,7 @@ the value `"Jig UART On"`:
The keyword `ADC_JIG_UART_ON` seems especially interesting. Why? Well, the driver has to know what to do The keyword `ADC_JIG_UART_ON` seems especially interesting. Why? Well, the driver has to know what to do
with each measured resistance. It would make sense that we call the constant which contains the resistance with each measured resistance. It would make sense that we call the constant which contains the resistance
something like that. Additionally, it is the only constant name name that does not immediately hint at its something like that. Additionally, it is the only constant name that does not immediately hint at its
value or function. value or function.
So we search the kernel source for this keyword. Most occurences are just So we search the kernel source for this keyword. Most occurences are just
@@ -139,7 +139,7 @@ connect the phone's D- and D+ lines to the host USB's D- and D+. Hence the need
conversion for us and also deals with the timing of the data: The tiny board to which all cables lead to conversion for us and also deals with the timing of the data: The tiny board to which all cables lead to
basically just contains an *FT232RL* chip from *FTDI*. It is what does all the conversion and timing magic. basically just contains an *FT232RL* chip from *FTDI*. It is what does all the conversion and timing magic.
Since I don't want to accidentally brick by phone my frying it with 3.3V or 5V - though I think that damaging Since I don't want to accidentally brick by phone by frying it with 3.3V or 5V - though I think that damaging
the hardware with 5V is pretty difficult - I did not connect the USB's 5V to the *FT232*'s VCC port. the hardware with 5V is pretty difficult - I did not connect the USB's 5V to the *FT232*'s VCC port.
Booting up the device, we start to see data being sent via serial! Booting up the device, we start to see data being sent via serial!
@@ -224,7 +224,7 @@ Device Tree files, the *S7* uses the Exynos 8890 SoC. This one is not in mainlin
required to port it from the [downstream kernel](https://github.com/ivanmeler/android_kernel_samsung_universal8890/) into mainline. required to port it from the [downstream kernel](https://github.com/ivanmeler/android_kernel_samsung_universal8890/) into mainline.
### Device Support ### Device Support
The challenge that follows, required I don't brick my phone, is the kernel support for the SoC's hardware. The challenge that follows, provided I don't brick my phone, is the kernel support for the SoC's hardware.
#### GPU #### GPU
The GPU of the Exynos 8890 SoC is a Mali-T880 from ARM. While there is no "official" FOSS-driver for it, one The GPU of the Exynos 8890 SoC is a Mali-T880 from ARM. While there is no "official" FOSS-driver for it, one

View File

@@ -1,17 +0,0 @@
-----BEGIN PGP SIGNATURE-----
iQJMBAABCAA2FiEEvBU+39pRCqHFhwUCToYVYy9G5oAFAmGjjakYHHBhcGF0dXR1
d2F3YUBwb2x5bm9tLm1lAAoJEE6GFWMvRuaA4dEP/1gdY+0MPilvt2MVVDOpeewZ
arHmDLticrsVWnftbGbvNHfRagcqfyPDA4chk7dLFUhTz2DDr7qzvMF2XbY1o0yc
hZdElIROcSGJz8OpW/2Cb2+bsH5DOz4RTBHXCAOhAlQnu9OWOScsg0kCwg1dyzfO
OdcfFeUAO4JRDjzREZ5JEiI788e3CXt2XP3TVwF82pExYMQt7ii1wQQZXl0hIZmA
QhmtUeLs+iUQ1JEnUJZMRDl1iJMxsirEtxAKvOCE/Mtol29j6j+83xrTyDahl1u9
ORnxFcznwGm8Mlw0bvFiEIWwAf7hCCYIcLjmh52cfLSrL+CsKOscGR79i6hIBAR9
hyYB/jg1Ug35J7eN5Lx2Qj0gf0LcGIzXukuE7PqNONzhDWcTsu43paXD2muSLyi7
y7sr1OQWcNbXKbS2+bbRtpJAqphrhdACIcAd8JKaJbQxxjfhETIT3bLUaRsLryZq
7CIUKIa/5gx/fqXbovIF7JOIi08ItxKAZtksi+viGZRJgghoVmPJftLcNO8JwZ5Y
TtfF03dRFRR72EfXn2glkeCN/XKHkmzKk35XFWdC80LB79cazxRINCjVv+1G4LFp
13HCL/MBMku5kOzxoWwb6b7mZSXf26QLRuBXaQd/uCnI5V1Y3RDzMje/Uwcqfpq5
9Nwx1i+VdelP7au0L/La
=QVca
-----END PGP SIGNATURE-----

View File

@@ -1,17 +0,0 @@
-----BEGIN PGP SIGNATURE-----
iQJMBAABCAA2FiEEvBU+39pRCqHFhwUCToYVYy9G5oAFAmGjjakYHHBhcGF0dXR1
d2F3YUBwb2x5bm9tLm1lAAoJEE6GFWMvRuaAGeIP/0hNo1wq7xXKWYhQUVqk5mNq
2sPPfxg3+6KNuidUmxnwIpXsIPEw7jJ3xh74hb6afWHH0ZitrIUoLszkcOkEJaNe
Zz+5UfsQybdYbWUsmpJCNK9QKEvwOa7B1TLUeI1ZR6B9KVVIUApg8AEYzBGce5ON
MroYc/oQgEZCm5cSmuVc/+yds/gFwvJUmEZOFbXyhl1jGr499fG5Q/khZ0bwPZP5
swbUBij0A8nBHiso5k+pDPEUIS6mE6hKZBH+gr9/CefCj1LCyiKRDjeNujZqmiRH
r2w/3nARAfr0Vd7X7P/Zsz3iKfP4/SEbHqY6mSGTWyahWajuiJWDMnM6HhIFHXbE
RdH1HSDB2bj93TGHaNDwG/4l0FHyqGHmhtVMo243fXJv1zaLlSabTcXFa0wPEToA
Z4OQcZWjDzumz2OnbBInaev8Q3aQsvkQERs3jbAw9HaKJqn/tOhPCFqrZRlvyhmV
IvcWoPYtqaRA0MCjK7eDlMN1vcllR8owNXLN/xTKoNDPDAKOezalF2NgwNrBDqIM
WEQBHRRa3Atm4aAOH8h8SZ+zYO63cmndCdpRA6eSmZ1lOO5NhmN9OfUX/ulLKFP9
YEefJ0bfANnz2tjaogWAwQeZYSH5Pj51VvmQnwX5D1taBQXqMJbyMFfdsU45JQNu
GYM5qpVHR7NDrj5X4uAG
=t56n
-----END PGP SIGNATURE-----

View File

@@ -1,17 +0,0 @@
-----BEGIN PGP SIGNATURE-----
iQJMBAABCAA2FiEEvBU+39pRCqHFhwUCToYVYy9G5oAFAmGjjakYHHBhcGF0dXR1
d2F3YUBwb2x5bm9tLm1lAAoJEE6GFWMvRuaA91MP+wX5e2v6CuaOEewjOFwhPWa1
Naq31RhJvuYD3/leIVy4fZa+EkBgk9QNgnavOeKkM1bHlc6bZggE/sLwnTuhoXFX
xSHil8oaF/7rNdgjjNUq8+N3Zo7GSGWJzOyZua/B91mubEDbwF9soqo2mXFzZBC3
ZJODsWcK+l3lz9oiNGGxfa3NbkoNRF2falEYckeUoGg84xYknoSx8aGo8cbmyiRO
aorTF7NtQMyhMXC4CfSoy/wjit1x+JYa11lr7epF4oy7yx+n0e5b58COkA5AEiL9
XGzKe5IfphENj6tL6fnoiO80rXRQ34FaIjSLr/8kwKz/AQ5UIGeRybGPUdTaOz5D
u9AVGD5HvLeUdwVilCf5Lhmutu9+0y86HImPoGYS6n7jZApIDelayaRHhmrcYT29
yxCxHg9ulKBjq6Owbdqhfyf9oWB2gnHYnM8iD7bvJGkHJlLvIDaSsNyiOJeLs50S
hU/UGuAnKRAqHRhZuYhW7Z8NVwxXeJ21lwCF3scxfSn65oAJKwSjIWIXnoEhzRaA
hkLiL4Gq22simb/coNn94VC7xvY439Rvaes86ZYaLsyi5lMJUGtOFrmL33v0iCDB
FS2l42UtMJxQsRezd8gd7IVRJrJynwymHwpu/8YuNP3n1kzv9cva/B7fsccBS5li
1/lQA/A75nkqAqKyO/16
=iSmJ
-----END PGP SIGNATURE-----

View File

@@ -1,17 +0,0 @@
-----BEGIN PGP SIGNATURE-----
iQJMBAABCAA2FiEEvBU+39pRCqHFhwUCToYVYy9G5oAFAmGjjakYHHBhcGF0dXR1
d2F3YUBwb2x5bm9tLm1lAAoJEE6GFWMvRuaACLAP/2b44Gl5t6beFRRTDuwEWTtY
q+88M9VFYJqoU9Fmvjeeiz5cdBi4PJRVK+U3He+Mxp8EcL64u3XUsKY6OnVJQ2t5
dm1/uWEI8TUIYHGOKyqZtn0TrWUF6NoFsE/KmSWCq307dD0RRtLzDm6ztkE1XoPJ
U/NP54ScCHA9StZPMA6UkLqv6pfV42eiCz3c42m4OfhAq4Ch1q5Nyuyh+GokQVA0
wFtTLzXbJxJZgRvxLhT2tyBMWn2+kp6TfR6ZGkbzzdSObM7v1Cj5ZY0IVAt5wVQC
JEXY5GZ/nyw5zzLyqkZjoDvzlhDCOKz4866uZr87rMAeFpmFb7YKed7sWD/72a8b
z2dg+i8HOM7fm2FFffyPVROZ8WS1v3sZBayFQsNCMZ5hCKJfzqsIIUCYwZ6frNJ/
BMv4bB5tSjmcEMD+pCQNTnRdqLdlZfRRAVIpwyPGPlzS9y+v6wNniyupM0AkeQii
xS5rSXWEBok7Z8hOSX0J206aDDdXVkHhnR80JU3DC3SfDBohAMSfG/9bwnlYBZcS
o3/P3q0u1alfKOgCJorb4sq3t2OdHsTrS3MYWgiyLNFKKfQktenAkToSecP0zgXe
qVbrCuQmZnFuDjtPh45kEK61i/5YveLfHaZX2unHsja4V/vXPOsinvJVMnBsfEzp
1SnNcGw4v1jzT/7Gx8Z3
=eW+1
-----END PGP SIGNATURE-----

View File

@@ -1,17 +0,0 @@
-----BEGIN PGP SIGNATURE-----
iQJMBAABCAA2FiEEvBU+39pRCqHFhwUCToYVYy9G5oAFAmGjjakYHHBhcGF0dXR1
d2F3YUBwb2x5bm9tLm1lAAoJEE6GFWMvRuaAymcQAKoksLNNyoEuE4/wzaNv56UA
yqg+ylYz0vHnDYPgvawLolkQfrgbKzGa0zN3ugMvHR7sVQxdsT4BqmjSSs0CR1P9
aWIfBBoPAB0OzKh7M64/K2vVeok/tbfa2Y5DFYGZbBuKDxJwr40Tfu4kJNk89LZQ
KGed9+ZJo8STtdy7VjNL5sQIBMtGfFtNW9cYVR5Fr4uF/m2FKc6zYLXA5t3tbIWD
RzIjD1s6GYLeLmj0ZGtgopLWX6ERIAtiveCn+LmPYtU+wsPBOv8Xg8+nQWq6bwpO
8WHuQD049MZ/XRmeNnlBcfg7b1TIsZD5fya+rD85sKEXFWs4QMraDeAII+aJoZpd
QyDafn7gj37E6ej+Q5qCuh7hsWslC4YaQek0GRlCygz/+Jn+NtnwXaNVEJs22j7V
Lj6+2cUExQAX7MySNDdbwyS/PUrYrVLLagx6NW2OdII3UBz+A4srFb9RQ6dttWOE
CzTHVY7BX4QalJyjc7Yex5do8lH/PZ23IsCSFE/r0I0kJes2Raq9eTyAISpvQSeZ
HfvkiyrW3feOVfSjp64L7Y+lxmtgfo6HJhUZcb21OwlpLYJxRin+QOWHWbeg+fx0
0EpJoKETofj8g5ErdZajFezr6odM27M3XGrTJIJJO6OqLv7fUYWc2Xmuf9+DXGTR
fjVwJtmEIo/jR92saXgg
=OXjT
-----END PGP SIGNATURE-----

View File

@@ -1,17 +0,0 @@
-----BEGIN PGP SIGNATURE-----
iQJMBAABCAA2FiEEvBU+39pRCqHFhwUCToYVYy9G5oAFAmGjjakYHHBhcGF0dXR1
d2F3YUBwb2x5bm9tLm1lAAoJEE6GFWMvRuaAFAEP/0MMomPeqy56TnDjvG+fFEPC
PPDexOXD8h0KVBGUdFGS7FPBn/O4ByKVE6Ki/y/2YttBt+P3RceT1eNjY+rPxFu9
B7hcjli72G6dZ4bzofbNl3huG4oWmDEpX9CT87lL8vGU/4CqaKIk/dfBxuFPwqus
5CyMX/ECMTjRNbQ75EKGE4vINht45pWFLzZUp+DKw4K2idOaQ8T+8vAKF0o10/Qr
npDCAy0hIY9HWmYEI7JheUfMrw5jxYJ6vXIGHmsiVqX8DXxGpXXqevDhkFa6QEbA
sgENJr5EvCR2ZeM3e566qYXSibCSfq58aXEVkt9yXrNrj0Q7Iz/uD7J5lR64e+rD
Hv43p/lKbFRi7UAYpWR8nUXSX8wbzTETgT/WUeExD0AWIsyYAj33R7U1UngCL9qI
IrkrPKnxBFRQTxl6v+MxEN7xAtKf9BWtbm+VQv+xuPtIE1dUof6oUKGA+f9qFrnR
XucIZrGNbOfwfJ3P4w+crvI2WgqvH7vQSJbQPKNEXvQP9rYh5L7nG1IXqaHRQnuO
kn9EcG/uQOkZUeo+8uvBJvSmcE9DiyYFfWvoDvpqtMfdolD+n8HXNfGFaGkHZ7+b
RgFWmIGshVZo968y6iP9zyubdViF5JWl8r4pR6Y9MIbjiXOfgTPMpYpFL7lJQ2kr
S1EEc4E/Axw0VYSk2jTw
=WyMf
-----END PGP SIGNATURE-----

View File

@@ -1,17 +0,0 @@
-----BEGIN PGP SIGNATURE-----
iQJMBAABCAA2FiEEvBU+39pRCqHFhwUCToYVYy9G5oAFAmGjjakYHHBhcGF0dXR1
d2F3YUBwb2x5bm9tLm1lAAoJEE6GFWMvRuaAE28P/0MZqiLeSDVP+W8eKaXrWh5i
BfKDbRefdtV8/Ybs0MSCU9FyRv/PAvN7uA6KsBwptyJD8YMcJt1f8npjjN/E4In6
uHz3EjjQmM5h4GIvnchN6IKL0CzkZspLH7thd5HXDYey7iEnu/b2P3W8MGdJbBYx
x9dnGTDLm0y+x5FV8Lpe/UCgL1xTli0lpmUMKqzg58WFtrU2YD0y6jircxOKxyeO
Rp0Sb2G/vfZL9oKVdK28zZ6CINCmNbYTaI/tqwTxoM9tB/+He+H4RaiAfFzU2/Ri
jOm48xwr2Vmx2jvBk6mvQppIRtmy5tUOB9pFSTjQBCHL3hBUbN/nImAhpDl5u7CQ
Y1xK60i42YFyiOj6vD551XoQNmgiJ7zVuJ3wy+k03wl1RujbRxnPkm2vwhPVPBBL
1IWxoUPyTwpD6f/td2sZdqYGa8H+lRx8hjzwAw55zCF6KdCvLSWz6DBZUrQo1Wji
nwVHcOtidfo3l9fH3xR8tshM2Rsv6XuKtyp3WkLJajW0r2et/bAyz29oU0BtGUlE
dmjhCllGgtfJWz8r/XGiHgNQqiuJT3fMoQ2kVDrDMU1W4ffxleJGQbYDfhPOq1Pa
JGE/JhaDAxhRXUlPdmVkkzuYE6WVwJu6FvaBzi9DJ2CkUl1UYk6jXl8n0pFrplXc
AG9V+U0UmrLXc5ILN0Y6
=bWDk
-----END PGP SIGNATURE-----

View File

@@ -0,0 +1,125 @@
<!-- title: Running Prosody on Port 443 Behind traefik 2: Electric ALPN -->
<!-- description: In this blog post, I tell you how I changed my setup for proxying my XMPP server using traefik -->
<!-- render: yes -->
Hello everyone. Long time, no read.
In 2020, I published a post titled "[Running Prosody on Port 443 Behind traefik](https://blog.polynom.me/Running-Prosody-traefik.html)", where I described how I run my XMPP server
behind the "application proxy" [*traefik*](https://github.com/traefik/traefik).
I did this because I wanted to run my XMPP server *prosody* on port 443, so that the clients connected
to my server can bypass firewalls that only allow web traffic. While that approach worked,
over the last three years I changed my setup dramatically.
While migrating my old server from *Debian* to *NixOS*, I decided that I wanted a website
hosted at the same domain I host my XMPP server at. This, however, was not possible with
*traefik* back then because it only allowed the `HostSNI` rule, which differentiates TLS
connections using the sent *Server Name Indication*. This is a problem, because a connection
to `polynom.me` the website and `polynom.me` the XMPP server both result in the same SNI being
sent by a connecting client.
Some time later, I stumbled upon [*sslh*](https://github.com/yrutschle/sslh), which is a
tool similar to *traefik* in that it allows hosting multiple services on the same port, all
differentiated by the SNI **and** the ALPN set by the connecting client. ALPN, or *Application-Layer Protocol Negotiation*, is an extension
to TLS which allows a connecting client to advertise the protocol(s) it would like to use
inside the encrypted session [(source)](https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation). As such, I put
*sslh* in front of my *traefik* and told it to route XMPP traffic (identified with an ALPN
of `xmpp-client`) to my prosody server and everything else to my *traefik* server. While this
worked well, there were two issues:
1. I was not running *sslh* in its ["transparent mode"](https://github.com/yrutschle/sslh/blob/master/doc/config.md#transparent-proxy-support), which uses some fancy iptable rules to allow the services behind it to see a connecting client's real IP address instead of just `127.0.0.1`. However, this requires more setup to work. This is an issue for services which enforce rate limits, like *NextCloud* and *Akkoma*. If one of theses services gets hit by many requests, all the services see are requests from `127.0.0.1` and may thus rate limit (or ban) `127.0.0.1`, meaning that all - even legitimate - requests are rate limited. Additionally, I was not sure if I could just use this to route an incoming IPv6 request to `127.0.0.1`, which is an IPv4 address.
2. One day, as I was updating my server, I noticed that all my web services were responding very slowly. After some looking around, it turned out that *sslh* took about 5 seconds to route IPv6 requests, but not IPv4 requests. As I did not change anything (besides update the server), to this day I am not sure what happened.
Due to these two issues, I decided to revisit the idea I described in my old post.
## The Prosody Setup
On the prosody-side of things, I did not change a lot compared to the old post. I did, however,
migrate from the `legacy_ssl_*` options to the newer `c2s_direct_tls_*` options, which
[replace the former](https://hg.prosody.im/trunk/file/tip/doc/doap.xml#l758).
Thus, my prosody configuration regarding direct TLS connections now looks like this:
```lua
c2s_direct_tls_ports = { 5223 }
c2s_direct_tls_ssl = {
[5223] = {
key = "/etc/prosody/certs/polynom.me.key";
certificate = "/etc/prosody/certs/polynom.me.crt";
};
}
```
## The *Traefik* Setup
On *traefik*-side of things, only one thing really changed: Instead of just having a rule using
`HostSNI`, I now also require that the connection with the XMPP server advertises an ALPN
of `xmpp-client`, which is specified in the
[appropriate XMPP spec](https://xmpp.org/extensions/xep-0368.html). From my deployment
experience, all clients I tested (*Conversations*, *Blabber*, *Gajim*, *Dino*, *Monal*, [Moxxy](https://moxxy.org))
correctly set the ALPN when connecting via a direct TLS connection.
So my *traefik* configuration now looks something like this (Not really, because I let NixOS
generate the actual config, but it is very similar):
```yaml
tcp:
routers:
xmpps:
entrypoints:
- "https"
rule: "HostSNI(`polynom.me`) && ALPN(`xmpp-client`)"
service: prosody
tls:
passthrough: true
# [...]
services:
prosody:
loadBalancer:
servers:
- address: "127.0.0.1:5223"
http:
routers:
web-secure:
entrypoints:
- "https"
rule: "Host(`polynom.me`)"
service: webserver
tls:
```
The entrypoint `https` is just set to listen on `:443`. This way, I can route IPv4 and IPv6
requests. Also note the `passthrough: true` in the XMPP router's `tls` settings. If this is
not set to `true`, then *traefik* would terminate the connection's TLS session before passing
the data to the XMPP server.
However, this config has one really big issue: In order
to have the website hosted at `polynom.me` be served using TLS, I have to set the
router's `tls` attribute. The *traefik*
documentation says that "*If both HTTP routers and TCP routers listen to the
same entry points, the TCP routers will apply before the HTTP routers. If no matching route
is found for the TCP routers, then the HTTP routers will take over.*"
[(source)](https://doc.traefik.io/traefik/routing/routers/#general_1).
This, however, does not seem to be the case if a HTTP router (in my example with ```Host(`polynom.me`)```) and a TCP router (in my example with ```HostSNI(`polynom.me`)```) respond to the same
SNI **and** the HTTP router has its `tls` attribute set. In that case, the HTTP router appears
to be checked first and will complain, if the sent ALPN is not one of the
[HTTP ALPNs](https://developer.mozilla.org/en-US/docs/Glossary/ALPN), for example when
connecting using XMPP. As such we can connect to the HTTP server but not to the
XMPP server.
It appears to be an issue that [I am not alone with](https://github.com/traefik/traefik/issues/9922), but also
one that is not fixed. So I tried digging around in *traefik*'s code and tried a couple of
things. So for my setup to work, I have to apply [this patch](https://github.com/PapaTutuWawa/traefik/commit/36f0e3c805ca4e645f3313f667a6b3ff5e2fe4a9) to *traefik*. With that, the issue *appears*
to be gone, and I can access both my website and my XMPP server on the same domain and on the
same port. Do note that this patch is not upstreamed and may break things. For me, it
works. But I haven't run extensive tests or *traefik*'s integration and unit tests.
## Conclusion
This approach solves problem 2 fully and problem 1 partially. *Traefik* is able to route
the connections correctly with no delay, compared to *sslh*. It also provides my web services
with the connecting clients' IP addresses using HTTP headers. It does not, however, provide
my XMPP server with a connecting client's IP address. This could be solved with some clever
trickery, like telling *traefik* to use the [*PROXY* protocol](https://doc.traefik.io/traefik/routing/services/#proxy-protocol) when connecting to prosody,
and enabling the [`net_proxy`](https://modules.prosody.im/mod_net_proxy.html) module. However,
I have not yet tried such a setup, though I am very curious and may try that out.

View File

@@ -0,0 +1,102 @@
<!-- title: Signing Android Apps Using a YubiKey (on NixOS) -->
<!-- render: yes -->
In my spare time, I currently develop two Android apps using *Flutter*: [AniTrack](https://codeberg.org/PapaTutuWawa/anitrack), a
simple anime and manga tracker based on my own needs, and [Moxxy](https://moxxy.org), a modern XMPP
client. While I don't provide release builds for AniTrack, I do for Moxxy. Those
are signed using the key-pair that Flutter generates. I thought to myself: "Wouldn't it be cool if I could keep
the key-pair on a separate device which does the signing for me?". The consequence
of this thought is that I bought a *YubiKey 5c*. However, as always, using it for my
purposes did not go without issues.
The first issue is that the official [*Android* documentation](https://developer.android.com/build/building-cmdline#deploy_from_bundle)
says to use the `apksigner` tool for creating the signature. [The *YubiKey* documentation](https://developers.yubico.com/PIV/Guides/Android_code_signing.html), however,
uses `jarsigner`. While I, at first, did not think much of it, *Android* has
[different versions of the signature algorithm](https://source.android.com/docs/security/features/apksigning/): `v1` (what `jarsigner` does), `v2`, `v3`, `v3.1` and
`v4`. While it seems like it would be no problem to just use `v1` signatures, *Flutter*, by default,
generates `v1` and `v2` signatures, so I thought that I should keep it like that.
So, the solution is to just use `apksigner` instead of `jarsigner`, like [another person on the Internet](https://geoffreymetais.github.io/code/key-signing/) did.
But that did not work for me. Running `apksigner` like that makes it complain that `apksigner` cannot
access the required `sun.security.pkcs11.SunPKCS11` Java class.
```
> /nix/store/ib27l0593bi4ybff06ndhpb8gyhx5zfv-android-sdk-env/share/android-sdk/build-tools/34.0.0/apksigner sign \
--ks NONE \
--ks-pass "pass:<YubiKey PIN>" \
--provider-class sun.security.pkcs11.SunPKCS11 \
--provider-arg ./provider.cfg \
--ks-type PKCS11 \
--min-sdk-version 24 \
--max-sdk-version 34 \
--in unsigned.apk \
--out signed.apk
Exception in thread "main" java.lang.IllegalAccessException: class com.android.apksigner.ApkSignerTool$ProviderInstallSpec cannot access class sun.security.pkcs11.SunPKCS11 (in module jdk.crypto.cryptoki) because module jdk.crypto.cryptoki does not export sun.security.pkcs11 to unnamed module @75640fdb
at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:392)
at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:674)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:489)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
at com.android.apksigner.ApkSignerTool$ProviderInstallSpec.installProvider(ApkSignerTool.java:1233)
at com.android.apksigner.ApkSignerTool$ProviderInstallSpec.access$200(ApkSignerTool.java:1201)
at com.android.apksigner.ApkSignerTool.sign(ApkSignerTool.java:343)
at com.android.apksigner.ApkSignerTool.main(ApkSignerTool.java:92)
```
It may only be an issue because I use NixOS, as I
cannot find another instance of someone else having this issue. But I still want my APK signed using the key-pair
on my *YubiKey*. After a lot of trial and error, I found out that I can force Java to export certain classes
using the `--add-exports` flag. Since `apksigner` complained that the security classes are not exported to its
unnamed class, I had to specify `--add-exports sun.security.pkcs11.SunPKCS11=ALL-UNNAMED`.
## My Setup
TL;DR: I wrapped this entire setup (minus the Gradle config as that's a per-project thing) into a fancy [script](https://codeberg.org/PapaTutuWawa/bits-and-bytes/src/branch/master/src/flutter/build.sh).
My provider configuration for the signature is exactly like the one provided in [previously mentioned blog post](https://geoffreymetais.github.io/code/key-signing/#set-up-your-own-management-key),
with the difference that I cannot use the specified path to the `opensc-pkcs11.so` as I am on NixOS, where such
paths are not used. So in my setup, I either use the Nix REPL to build the derivation for `opensc` and then
use its `lib/opensc-pkcs11.so` path (`/nix/store/h2bn9iz4zqzmkmmjw9b43v30vhgillw4-opensc-0.22.0` in this case) for testing or, as
used in [AniTrack](https://codeberg.org/PapaTutuWawa/anitrack/src/branch/master/flake.nix), let Nix figure out the path by building
the config file from within my Nix Flake:
```nix
{
# ...
providerArg = pkgs.writeText "provider-arg.cfg" ''
name = OpenSC-PKCS11
description = SunPKCS11 via OpenSC
library = ${pkgs.opensc}/lib/opensc-pkcs11.so
slotListIndex = 0
'';
# ...
}
```
Next, to force Java to export the `sun.security.pkcs11.SunPKCS11` class to `apksigner`'s unnamed class, I added `--add-exports sun.security.pkcs11.SunPKCS11`
to the Java command line. There are two ways of doing this:
1. Since `apksigner` is just a wrapper script around calling `apksigner.jar`, we could patch the wrapper script to include this parameter.
2. Use the wrapper script's built-in mechanism to pass arguments to the `java` command.
While option 1 would work, it would require, in my case, to override the derivation that builds my Android SDK environment, which I am not that fond of.
Using `apksigner`'s way of specifying Java arguments (`-J`) is much easier. However, there is a little trick to it: When you pass `-Jsomething` to `apksigner`,
the wrapper scripts transforms it to `java -something`. As such, we cannot pass `-Jadd-exports sun.security.pkcs11.SunPKCS11` because it would get transformed
to `java -add-exports sun.security.[...]`, which is not what we want. To work around this, I quote the entire parameter to trick Bash into thinking that I'm
passing a single argument: `-J"-add-exports sun.security.pkcs11.SunPKCS11"`. This makes the wrapper append `--add-exports sun.security.pkcs11.SunPKCS11` to the
Java command line, ultimately allowing me to sign unsigned Android APKs with the key-pair on my *YubiKey*.
Since signing a signed APK makes little sense, we also need to tell Gradle to *not* sign the APK. In the case of Flutter apps, I modified the `android/app/build.gradle`
file to use a null signing config:
```gradle
android {
// ...
buildTypes {
release {
// This prevents Gradle from signing release builds.
// I don't care what happens to debug builds as I'm not distributing them.
signingConfig null
}
}
}
```

8
flake.lock generated
View File

@@ -36,16 +36,16 @@
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1638239011, "lastModified": 1689449371,
"narHash": "sha256-AjhmbT4UBlJWqxY0ea8a6GU2C2HdKUREkG43oRr3TZg=", "narHash": "sha256-sK3Oi8uEFrFPL83wKPV6w0+96NrmwqIpw9YFffMifVg=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "a7ecde854aee5c4c7cd6177f54a99d2c1ff28a31", "rev": "29bcead8405cfe4c00085843eb372cc43837bb9d",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "NixOS",
"ref": "21.11", "ref": "nixpkgs-unstable",
"repo": "nixpkgs", "repo": "nixpkgs",
"type": "github" "type": "github"
} }

View File

@@ -2,7 +2,7 @@
description = "The blog hosted at https://blog.polynom.me"; description = "The blog hosted at https://blog.polynom.me";
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/21.11"; nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
assets.url = "git+https://git.polynom.me/polynom.me/shared-assets.git"; assets.url = "git+https://git.polynom.me/polynom.me/shared-assets.git";
}; };
@@ -16,9 +16,17 @@
in { in {
packages = forAllSystems (system: let packages = forAllSystems (system: let
pkgs = import nixpkgs { inherit system; }; pkgs = import nixpkgs { inherit system; };
tailwindWithTypography = pkgs.nodePackages.tailwindcss.overrideAttrs (old: {
plugins = [
pkgs.nodePackages."@tailwindcss/typography"
];
});
in { in {
default = pkgs.callPackage ./pkgs/blog.nix { default = pkgs.callPackage ./pkgs/blog.nix {
shared-assets = assets.packages.${system}.default; shared-assets = assets.packages.${system}.default;
inherit tailwindWithTypography;
}; };
}); });

28
input.css Normal file
View File

@@ -0,0 +1,28 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
article > p > a, h1, h2, h3, h4, h5, h6 {
@apply text-indigo-400 !important;
}
article > p > strong, code {
@apply text-white !important;
}
article > h1, h2, h3, h4, h5, h6 {
@apply text-indigo-400 !important;
}
body {
background-color: #212121;
}
html {
@apply text-white;
}
a {
@apply text-indigo-400 !important;
}
}

View File

@@ -1,13 +1,10 @@
<div class="horizontal-center"> <!-- Post item -->
<div class="post-list-item"> <div class="flex flex-col pt-4">
<h2><a class="post-list-item-title" href="/{{ slug }}.html">{{ title }}</a></h2> <a href="/{{ slug }}.html"><h1 class="text-indigo-400 prose prose-lg text-xl">{{ title }}</h1></a>
<span class="text-md mt-2">Posted on {{ date }}</span>
<p><b>&gt; {{ date }}</b></p> <!-- Blurp -->
<span class="prose text-white mt-4">
<p class="post-summary"> {{ summary }}
<div class="quote text"> </span>
{{ summary }}...
</div>
</p>
</div>
</div> </div>

View File

@@ -1,5 +1,4 @@
<div class="post-list"> <!-- Container for posts -->
<div class="vertical"> <div class="mx-auto">
{{ content }} {{ content }}
</div> </div>
</div>

View File

@@ -1,50 +1,43 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html>
<head> <head>
<title>{{ title }}</title> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="/assets/css/index.css" rel="stylesheet" />
<link href="/assets/css/code.css" rel="stylesheet" />
<link href="/feed.xml" type="application/atom+xml" rel="alternate" title="Moxxy Blog" />
<meta property="og:title" content="{{ title }}" /> <meta property="og:title" content="{{ title }}" />
<meta property="og:description" content="{{ description }}" /> <meta property="og:description" content="{{ description }}" />
<meta charset="UTF-8" /> <!-- Blog -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1"> <link rel="alternative"
<link rel="stylesheet" href="{{ page_assets }}/css/main.css" /> type="application/rss+xml"
<link rel="stylesheet" href="/assets/css/blog.css" /> title="PapaTutuWawa's Blog"
<link rel="stylesheet" href="/assets/css/syntax.css" /> href="https://{{ blog_url }}/atom.xml" />
<link rel="me" href="https://fosstodon.org/@polynomdivision" />
<!-- Optional MathJax -->
{{ mathjax_include }} {{ mathjax_include }}
<title>{{ title }}</title>
</head> </head>
<body> <body>
<div class="horizontal-center"> <div class="flex flex-col p-2 md:p-8 items-start md:w-4/5 mx-auto">
<div class="vertical header"> <!-- Header -->
<div id="header" class="horizontal"> <div class="flex flex-row self-center">
<img class="avatar" src="{{ page_assets }}/img/avatar.jpg" /> <img class="w-12 h-12 md:w-24 md:h-24 rounded-lg" src="{{ page_assets }}/img/avatar.jpg" alt="Profile picture"/>
<div class="ml-4 self-center">
<a class="self-center text-2xl font-bold" href="/">PapaTutuWawa's Blog</a>
<div class="vertical-center"> <ul class="list-none">
<span class="name-title">PapaTutuWawa's Blog</span> <li class="inline mr-8"><a href="/index.html">Posts</a></li>
<li class="inline mr-8"><a href="/atom.xml">RSS</a></li>
<div id="header-links"> <li class="inline mr-8"><a href="https://polynom.me">About</a></li>
<ul>
<li><a href="index.html">Posts</a></li>
<li><a href="/atom.xml">RSS</a></li>
<li><a href="https://polynom.me">About</a></li>
</ul> </ul>
</div> </div>
</div> </div>
</div>
<div class="horizontal-center">
{{ content }} {{ content }}
</div> </div>
<br />
<center class="footer">
Created by <i>PapaTutuWawa</i> with &lt;3 using
<a href="https://github.com/google/roboto">Roboto</a>,
<a href="https://github.com/RedHatOfficial/Overpass">Overpass</a> and
<a href="https://github.com/sunainapai/makesite">makesite</a>
</center>
</div>
</body> </body>
</html> </html>

View File

@@ -1,24 +1,19 @@
<div class="horizontal-center stretch-horizontally"> <!-- Container for posts -->
<div class="post"> <div class="mx-auto mt-4 w-full md:max-w-prose">
<article> <h1 class="text-indigo-400 text-3xl">{{ title }}</h1>
<h1>{{ title }}</h1>
<p>// Posted {{ date }}</p> <span class="text-md mt-2">Posted on {{ date }}</span>
<ul>
<li><a href="https://{{ git_url }}/PapaTutuWawa/blog.polynom.me/src/branch/master/content/blog/{{ file_name }}">Post source</a></li>
<li><a href="https://{{ git_url }}/PapaTutuWawa/blog.polynom.me/raw/branch/master/content/blog/{{ file_name }}.sig">Signed</a> with <a href="https://{{ email_gpg_url }}">this publickey</a></li>
</ul>
{{ mathjax_warning }}
<!-- Actual article -->
<article class="prose lg:prose-lg text-white mt-4">
{{ content }} {{ content }}
<br />
If you have any questions or comments, then feel free to send me an email
(Preferably with <a href="https://{{ email_gpg_url }}">GPG encryption</a>) to
{{ email_user }} [weird "a" with a circle] {{ email_domain }}.
</article> </article>
<!-- Common post footer -->
<div class="mt-6">
<span class="prose lg:prose-lg text-md text-white">
If you have any questions or comments, then feel free to send me an email (Preferably with GPG encryption)
to {{ email_user }} [at] {{ email_domain }} or reach out to me on the Fediverse at <a href="https://{{ fediverse_url }}">{{ fediverse_handle }}</a>.
</span>
</div> </div>
</div> </div>

View File

@@ -4,7 +4,8 @@
"blog_description": "My personal blog. Mainly tech stuff.", "blog_description": "My personal blog. Mainly tech stuff.",
"git_url": "git.polynom.me", "git_url": "git.polynom.me",
"blog_url": "blog.polynom.me", "blog_url": "blog.polynom.me",
"mastodon_url": "fosstodon.org/@polynomdivision", "fediverse_url": "social.polynom.me/PapaTutuWawa",
"fediverse_handle": "@PapaTutuWawa@social.polynom.me",
"email_gpg_url": "pki.polynom.me/pubkeys/papatutuwawa.pub", "email_gpg_url": "pki.polynom.me/pubkeys/papatutuwawa.pub",
"email_user": "papatutuwawa", "email_user": "papatutuwawa",
"email_domain": "polynom.me", "email_domain": "polynom.me",

View File

@@ -1,23 +1,29 @@
{ {
lib, stdenv lib, stdenv
, gnumake, imagemagick , gnumake, imagemagick
, shared-assets , python3
}: , shared-assets # For makesite.py
stdenv.mkDerivation { , tailwindWithTypography
}: let
pythonEnv = python3.withPackages (ps: with ps; [markdown pygments]);
in stdenv.mkDerivation {
pname = "blog"; pname = "blog";
version = "20211128"; version = "20230722";
src = ../.; src = ../.;
buildInputs = [ shared-assets gnumake imagemagick ]; buildInputs = [ shared-assets gnumake imagemagick ];
patchPhase = '' patchPhase = ''
sed -i Makefile -e "s|python ../shared-assets/makesite.py|python ${shared-assets}/bin/makesite.py|g" sed -i Makefile -e "s|python ../shared-assets/makesite.py|${pythonEnv}/bin/python ${shared-assets}/bin/makesite.py|g"
sed -i Makefile -e "s|tar -czf blog.tar.gz _site||g" sed -i Makefile -e "s|tar -czf blog.tar.gz _site||g"
''; '';
buildPhase = '' buildPhase = ''
make buildnosign make buildnosign
# Generate Tailwind CSS data
${tailwindWithTypography}/bin/tailwindcss --input ./input.css --output _site/assets/css/index.css
''; '';
installPhase = '' installPhase = ''

10
tailwind.config.js Normal file
View File

@@ -0,0 +1,10 @@
module.exports = {
content: [
"./layout/*.html",
],
theme: {
},
plugins: [
require('@tailwindcss/typography'),
],
}