Compare commits
No commits in common. "9aaa8ccffd23b93cab65ea3aeb48a66d220533e9" and "a32e0736c4f97468d7bfb4af0cefe891bb1e4de9" have entirely different histories.
9aaa8ccffd
...
a32e0736c4
2
.github/workflows/gh-pages.yml
vendored
@ -6,7 +6,7 @@ on:
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Git Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
2
Makefile
@ -16,7 +16,7 @@ LANGTOOL := silviof/docker-languagetool:latest
|
||||
DOCK := docker # maybe podman?
|
||||
|
||||
up:
|
||||
$(DOCK) run --rm -dn langtool -p127.0.0.1:8010:8010 $(LANGTOOL)
|
||||
$(DOCK) run --rm -dn langtool p127.0.0.1:8010:8010 $(LANGTOOL)
|
||||
down:
|
||||
$(DOCK) kill langtool
|
||||
pull:
|
||||
|
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 1.3 KiB |
@ -1,112 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="290.88196mm"
|
||||
height="74.000595mm"
|
||||
viewBox="0 0 1030.6841 262.20683"
|
||||
id="svg4491"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="devuan-logo-with-registered-trademark-sign.svg">
|
||||
<defs
|
||||
id="defs4493" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.78339844"
|
||||
inkscape:cx="264.00016"
|
||||
inkscape:cy="32.005932"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
fit-margin-top="10"
|
||||
fit-margin-left="10"
|
||||
fit-margin-right="10"
|
||||
fit-margin-bottom="10"
|
||||
inkscape:window-width="1366"
|
||||
inkscape:window-height="746"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata4496">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<cc:license
|
||||
rdf:resource="" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(262.59708,-302.16131)">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:150%;font-family:'Open Sans';-inkscape-font-specification:'Open Sans, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="716.98987"
|
||||
y="505.97049"
|
||||
id="text4470"
|
||||
sodipodi:linespacing="150%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan4472"
|
||||
x="716.98987"
|
||||
y="505.97049">®</tspan></text>
|
||||
<g
|
||||
style="display:inline"
|
||||
id="g4427"
|
||||
transform="translate(-283.36497,61.428879)">
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:100;font-stretch:normal;font-size:medium;line-height:150%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans Thin';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:19.91197014;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 369.8125,298.34766 a 9.9569807,9.9569807 0 0 0 -8.81445,14.58593 l 66.99414,127.49024 a 9.9569807,9.9569807 0 0 0 8.8125,5.32422 l 2.96484,0 a 9.9569807,9.9569807 0 0 0 8.83008,-5.35743 L 515,312.90234 a 9.9569807,9.9569807 0 0 0 -8.83008,-14.55468 l -2.37109,0 a 9.9569807,9.9569807 0 0 0 -8.83399,5.36132 L 438.26562,412.75 381.30469,303.69336 a 9.9569807,9.9569807 0 0 0 -8.82422,-5.3457 l -2.66797,0 z"
|
||||
id="path4401"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:100;font-stretch:normal;font-size:medium;line-height:150%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans Thin';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:20;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 541.45898,297.73633 a 10.001,10.001 0 0 0 -10,10 l 0,88.48633 c 0,14.8854 6.49876,28.38398 18.16016,37.26367 12.24914,9.32706 29.37532,12.87109 51.08594,12.87109 21.50233,0 38.53211,-3.55834 50.75195,-12.84375 11.8361,-8.84931 18.49609,-22.37012 18.49609,-37.29101 l 0,-88.48633 a 10.001,10.001 0 0 0 -10,-10 l -2.36914,0 a 10.001,10.001 0 0 0 -10,10 l 0,88.29883 c 0,9.41271 -2.81974,15.15179 -9.71484,20.4414 -6.30803,4.83925 -18.59119,8.38867 -37.16406,8.38867 -18.57288,0 -30.85603,-3.54942 -37.16406,-8.38867 -6.8951,-5.28961 -9.7129,-11.02869 -9.7129,-20.4414 l 0,-88.29883 a 10.001,10.001 0 0 0 -10,-10 l -2.36914,0 z"
|
||||
id="path4403"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:100;font-stretch:normal;font-size:medium;line-height:150%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans Thin';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:20;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 762.23633,297.25586 a 10.001,10.001 0 0 0 -8.88477,5.41016 L 686.40234,432.25 a 10.001,10.001 0 0 0 8.88282,14.58984 l 2.66601,0 a 10.001,10.001 0 0 0 8.89649,-5.43164 l 56.84961,-110.69922 56.58398,110.68164 a 10.001,10.001 0 0 0 8.9043,5.44922 l 2.36914,0 a 10.001,10.001 0 0 0 8.90039,-14.55859 L 774.09961,302.69727 a 10.001,10.001 0 0 0 -8.90234,-5.44141 l -2.96094,0 z"
|
||||
id="path4405"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:100;font-stretch:normal;font-size:medium;line-height:150%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans Thin';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:20;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 926.13477,297.73633 c -21.71059,0 -38.83679,3.54404 -51.08594,12.87109 -11.66148,8.87957 -18.16016,22.38011 -18.16016,37.26563 l 0,88.48437 a 10.001,10.001 0 0 0 10,10 l 2.36914,0 a 10.001,10.001 0 0 0 10,-10 l 0,-88.29687 c 0,-9.41288 2.81783,-15.15181 9.71289,-20.44141 6.30803,-4.83925 18.59126,-8.38867 37.16407,-8.38867 18.57294,0 30.85605,3.54944 37.16406,8.38867 6.89507,5.28961 9.71484,11.02853 9.71484,20.44141 l 0,88.29687 a 10.001,10.001 0 0 0 10,10 l 2.36914,0 a 10.001,10.001 0 0 0 10,-10 l 0,-88.48437 c 0,-14.92619 -6.66394,-28.45176 -18.50781,-37.30078 -12.21906,-9.27908 -29.24448,-12.83594 -50.74023,-12.83594 z"
|
||||
id="path4407"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:100;font-stretch:normal;font-size:medium;line-height:150%;font-family:'Fira Sans';-inkscape-font-specification:'Fira Sans Thin';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:9.99139977;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 262.70352,299.1501 c -16.6902,0 -31.61821,6.64211 -41.77029,19.04358 -2.94743,3.54165 -5.4048,7.50325 -7.41715,11.86761 -5.24033,11.36537 12.50043,3.04762 12.50043,19.57243 0,9.33503 -19.2702,40.30646 -17.7395,48.03331 2.25488,11.38259 6.32742,20.96483 12.67969,28.58438 10.18167,12.2129 25.08385,18.69188 41.74682,18.69188 l 71.79612,0 c 5.52169,-2e-4 9.99848,-4.47505 10.0008,-9.9968 l 0,-2.51777 c -1e-4,-5.52315 -4.47755,-10.0006 -10.0008,-10.0008 l -71.58108,0 c -11.57153,0 -19.03219,-3.40673 -25.32255,-10.89617 -5.80518,-6.91154 -9.80922,-19.80543 -9.80922,-39.48315 -2e-5,-19.67793 4.00408,-32.57162 9.80922,-39.48316 6.2904,-7.48924 13.75112,-10.89997 25.32255,-10.89997 l 71.58108,0 c 5.52325,-2e-4 10.0007,-4.47766 10.0008,-10.00081 l 0,-2.51396 c -2.2e-4,-5.52315 -4.47763,-10.0004 -10.0008,-10.0006 z"
|
||||
clip-path="none"
|
||||
id="path4409"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="scsssssccccscsssccccs" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccssscsc"
|
||||
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.57134259;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 56.200956,276.1655 c 351.111544,83.78964 18.967955,151.92346 18.967955,151.92346 -6.543555,1.04566 -11.821798,4.45425 -14.999489,9.63398 -3.569697,5.81872 -3.872178,13.6808 -0.538715,19.20842 4.056259,6.72618 9.195703,9.05293 13.628318,10.05499 6.973891,1.57656 12.603069,-0.93571 12.603069,-0.93571 0,0 169.799086,-50.45979 168.522696,-100.86283 -0.64075,-25.303 -52.0661,-68.10192 -198.183834,-89.02231 z"
|
||||
id="path4411"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 7.3 KiB |
@ -1,11 +1,4 @@
|
||||
<VirtualHost yowpdomain.example.com:443>
|
||||
AddType text/html .php
|
||||
DirectoryIndex index.php
|
||||
|
||||
<FilesMatch \.php$>
|
||||
SetHandler "proxy:unix:/run/php-fpm/www.sock"
|
||||
</FilesMatch>
|
||||
|
||||
# Dotfiles
|
||||
<FilesMatch "^\.">
|
||||
Deny from all
|
||||
|
Before Width: | Height: | Size: 41 KiB |
@ -1,31 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="0.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="306px" height="344.35px" viewBox="0 0 306 344.35" enable-background="new 0 0 306 344.35" xml:space="preserve">
|
||||
<path fill="#C37C2E" d="M302.107,258.262c2.401-4.159,3.893-8.845,3.893-13.053V99.14c0-4.208-1.49-8.893-3.892-13.052L153,172.175
|
||||
L302.107,258.262z"/>
|
||||
<path fill="#AB5921" d="M166.25,341.193l126.5-73.034c3.644-2.104,6.956-5.737,9.357-9.897L153,172.175L3.893,258.263
|
||||
c2.401,4.159,5.714,7.793,9.357,9.896l126.5,73.034C147.037,345.401,158.963,345.401,166.25,341.193z"/>
|
||||
<path fill="#D6AF46" d="M302.108,86.087c-2.402-4.16-5.715-7.793-9.358-9.897L166.25,3.156c-7.287-4.208-19.213-4.208-26.5,0
|
||||
L13.25,76.19C5.962,80.397,0,90.725,0,99.14v146.069c0,4.208,1.491,8.894,3.893,13.053L153,172.175L302.108,86.087z"/>
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M153,274.175c-56.243,0-102-45.757-102-102s45.757-102,102-102c36.292,0,70.139,19.53,88.331,50.968
|
||||
l-44.143,25.544c-9.105-15.736-26.038-25.512-44.188-25.512c-28.122,0-51,22.878-51,51c0,28.121,22.878,51,51,51
|
||||
c18.152,0,35.085-9.776,44.191-25.515l44.143,25.543C223.142,254.644,189.294,274.175,153,274.175z"/>
|
||||
</g>
|
||||
<g>
|
||||
<polygon fill="#FFFFFF" points="
|
||||
255,156.508
|
||||
243.666,156.508
|
||||
243.666,145.175
|
||||
232.334,145.175
|
||||
232.334,156.508
|
||||
221,156.508
|
||||
221,167.841
|
||||
232.334,167.841
|
||||
232.334,199.175
|
||||
243.666,199.175
|
||||
243.666,167.841
|
||||
255,167.841 "/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.6 KiB |
@ -1,3 +1,6 @@
|
||||
h1,h2,h3,h4,h5,h6 {
|
||||
@extend %headings !optional;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: rgb(18, 20, 21);
|
||||
@ -5,15 +8,13 @@ body {
|
||||
}
|
||||
|
||||
footer {
|
||||
padding: 1rem 3rem 0;
|
||||
padding: 1rem 3rem;
|
||||
}
|
||||
|
||||
figure {
|
||||
max-width: 42%;
|
||||
min-width: 13%;
|
||||
width: 42%;
|
||||
float: right;
|
||||
margin: 0 16px;
|
||||
text-align: center;
|
||||
figcaption {
|
||||
font-style: italic;
|
||||
}
|
||||
@ -25,53 +26,38 @@ figure {
|
||||
#content {
|
||||
main {
|
||||
background-color: rgb(24, 26, 27);
|
||||
margin: 3% 10% 0;
|
||||
margin: 3% 10%;
|
||||
padding: 3%;
|
||||
article {
|
||||
max-width: 90%;
|
||||
}
|
||||
.float {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
a:hover .heading {
|
||||
a:hover %headings {
|
||||
text-decoration: underline;
|
||||
color: cyan;
|
||||
}
|
||||
a {
|
||||
min-height: 48px;
|
||||
min-width: 48px;
|
||||
text-decoration: none;
|
||||
color: cyan;
|
||||
}
|
||||
a article {
|
||||
a li {
|
||||
color: lime;
|
||||
}
|
||||
}
|
||||
|
||||
ul.contents {
|
||||
.heading {
|
||||
font-size: 2rem;
|
||||
margin: 0;
|
||||
}
|
||||
list-style-image: url(data:0);
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#navbar {
|
||||
background-color: #222;
|
||||
li a:hover {
|
||||
background-color: #333;
|
||||
}
|
||||
.link-group li {
|
||||
float: right;
|
||||
}
|
||||
li {
|
||||
display: inline;
|
||||
float: left;
|
||||
}
|
||||
ul {
|
||||
li#right {
|
||||
float: right;
|
||||
}
|
||||
li {
|
||||
a:hover {
|
||||
background-color: #333;
|
||||
}
|
||||
display: inline;
|
||||
float: left;
|
||||
}
|
||||
list-style-type: none;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
|
@ -1,5 +1,6 @@
|
||||
---
|
||||
date: 2022-03-27T18:08:24Z
|
||||
draft: false
|
||||
aliases: []
|
||||
categories: ['meta']
|
||||
series: []
|
||||
|
@ -1,5 +1,6 @@
|
||||
---
|
||||
date: 2022-03-29T21:00:24Z
|
||||
draft: false
|
||||
aliases: []
|
||||
categories: ['meta']
|
||||
series: []
|
||||
|
@ -10,16 +10,9 @@ title: IT Apprentice
|
||||
description: This part of my blog is a collection of things I've learned as an apprentice working in IT.
|
||||
---
|
||||
|
||||
This page on my blog serves as an index of technologies I've learned or became better at while working as an apprentice in IT. :grinning:
|
||||
This section of my blog serves as an index of technologies I've learned or became better at as an apprentice working in IT. :grinning:
|
||||
|
||||
It also serves the purpose of the required documentation apprentices in Norway are supposed to do. :cowboy: :flushed:
|
||||
|
||||
It's mostly in relation to stuff learned at [SkyLabs AS](https://skylabs.no) where we run a captive portal service.
|
||||
But there is also some stuff from [Sircon AS](https://sircon.no).
|
||||
Those guys run hosting services, with a focus on cPanel/WordPress shared hosting.
|
||||
That would be "The WHM saga".
|
||||
Although when it comes to programming there would be some overlap, but don't dwell on that.
|
||||
Because at Sircon, I feel like they didn't want me working with code, but rather support only...
|
||||
It also serves the purpose of the required documentation apprentices in Norway are supposed to do. :flushed:
|
||||
|
||||
Here are lists of stuff I'll be writing about here;
|
||||
:x: marks not started :construction: marks work in progress :white_check_mark: marks complete!
|
||||
@ -28,32 +21,28 @@ Here are lists of stuff I'll be writing about here;
|
||||
### Python
|
||||
- :x: Flask :baby_bottle:
|
||||
- :x: SQLAlchemy :sake:
|
||||
- [:construction: MSAL (Microsoft Authentication Library) :banjo:](./msal)
|
||||
- :construction: MSAL (Microsoft Authentication Library) :banjo:
|
||||
### Browser JavaScript
|
||||
- :x: jQuery :calling:
|
||||
- [:construction: Handlebars.js :wavy_dash:](./handlebars)
|
||||
- :construction: Handlebars.js :wavy_dash:
|
||||
|
||||
## Programs / Tools
|
||||
- [:construction: Fail2ban :hammer:](./fail2ban)
|
||||
- [:construction: Docker :smiling_face_with_hearts:](./docker)
|
||||
- :construction: Fail2ban :hammer:
|
||||
- :construction: Docker :smiling_face_with_hearts:
|
||||
- :x: FreeRADIUS :crystal_ball:
|
||||
- :x: Postgres :floppy_disk:
|
||||
- [:construction: Ansible :gun:](./ansible)
|
||||
- [:white_check_mark: tzsp2pcap :chains:](./tzsp2pcap)
|
||||
- :construction: Ansible :gun:
|
||||
|
||||
## OS / Networking
|
||||
- [:construction: Debian :dolls:](./debian)
|
||||
- [:white_check_mark: Mikrotik :package:](./mikrotik)
|
||||
- [:white_check_mark: Cisco Meraki :cloud:](./meraki)
|
||||
- :x: Debian :dolls:
|
||||
- :construction: Mikrotik :package:
|
||||
- :x: Cisco Meraki :cloud:
|
||||
|
||||
## Azure
|
||||
- [:white_check_mark: App Registration :rocket:](./azure-app-registration)
|
||||
- :white_check_mark: App Registration :rocket:
|
||||
- :x: Active Directory :dizzy:
|
||||
|
||||
## Etc
|
||||
- [:white_check_mark: Linux desktop password reset :mage_man:](./linux-password-reset)
|
||||
|
||||
## The WHM saga (shortie)
|
||||
- [:white_check_mark: Wordpress :eyes:](./wordpress)
|
||||
- [:construction: cPanel :shit:](./cpanel)
|
||||
- [:construction: WHM :ok_hand:](./whm)
|
||||
- :white_check_mark: Wordpress :eyes:
|
||||
- :white_check_mark: cPanel :shit:
|
||||
- :white_check_mark: WHM :ok_hand:
|
||||
|
@ -15,7 +15,7 @@ You can find the App Registrations in Azure under Azure AD or directly by search
|
||||
Once there you can click the "New registration" button on the top left.
|
||||
Then you'll need to fill in name, account types and optionally a redirect URI.
|
||||
|
||||
{{< img src="apprentice/azure/app-registry.png" caption="The Azure App Registration page" hint=text >}}
|
||||
{{< img src="apprentice/azure/app-registry.png" caption="The Azure App Registration page" >}}
|
||||
|
||||
The first thing to do now is "Branding & properties"... haha.
|
||||
The app authenticates towards Microsoft with either a certificate or app secrets.
|
||||
@ -26,8 +26,8 @@ This is needed for newly created apps after 9th of November 2020 to prevent abus
|
||||
For this you'll need to add a "verified publisher domain" to the Azure Active Directory.
|
||||
This is the same as "Custom domain names" in Azure AD.
|
||||
They're usually added by TXT or MX DNS records.
|
||||
But may be added pretty easily with a simple .well-known/ HTTP challenge.
|
||||
Although when doing the HTTP challenge the domain won't become a custom domain name for the Azure AD tenant.
|
||||
But may be added pretty easily with a simple .well-known/ http challenge.
|
||||
Although when doing the http challenge the domain won't become a custom domain name for the Azure AD tenant.
|
||||
But rather bound to the specific app in question.
|
||||
|
||||
After that the actual MPN ID comes from the MPN, Microsoft Partner Network.
|
||||
@ -41,7 +41,7 @@ After that go to "Certificates & secrets".
|
||||
Microsoft always recommends using certificates for getting access codes.
|
||||
But the normal secrets are easier to configure.
|
||||
|
||||
Using certificates is the best if your app has good support so that all you need to do is download a cert from the server and upload that to Azure.
|
||||
Using certificates is best if your app has good support so that all you need to do is download a cert from the server and upload that to Azure.
|
||||
So either do that or add a "New client secret".
|
||||
The client secrets will have both the secret and an id, both are needed for authorization.
|
||||
When you create these you'll need to store them safely and put them wherever the app gets them from.
|
||||
@ -55,7 +55,7 @@ There is also the difference of "Application" and "Delegated" permissions.
|
||||
The Application permissions is for the app itself and need to be granted by the owner of the app.
|
||||
Whereas Delegated permissions are the ones that add stuff to the consent form, these lets the app do API requests on behalf of the end user and need to be granted by the end user or through admin consent.
|
||||
|
||||
{{< img src="apprentice/azure/api-permissions.png" caption="Azure API permissions" hint=text >}}
|
||||
{{< img src="apprentice/azure/api-permissions.png" caption="Azure API permissions" >}}
|
||||
|
||||
## Service principals
|
||||
Now to the hard part I guess.
|
||||
@ -66,7 +66,7 @@ If it's a tenant admin that's logging in that person may click the check for gra
|
||||
|
||||
Small and simple powershell script for adding the "service principal" to a tenant;
|
||||
|
||||
{{< highlight powershell >}}{{% asset "apprentice/azure/service-principal.ps1" %}}{{< /highlight >}}
|
||||
{{< highlight powershell >}}{{% asset "/apprentice/azure/service-principal.ps1" %}}{{< /highlight >}}
|
||||
|
||||
After the service principal is created in the Azure AD tenant with users that's going to consume the app.
|
||||
Admins may set "App Roles" per user under "Enterprise Applications" in Azure.
|
||||
|
@ -1,203 +1,13 @@
|
||||
---
|
||||
date: 2022-06-20T14:10:48Z
|
||||
draft: false
|
||||
draft: true
|
||||
aliases: []
|
||||
categories: ['documentation']
|
||||
series: ['apprentice']
|
||||
tags: ['linux', 'os']
|
||||
categories: ['various']
|
||||
series: []
|
||||
tags: ['various']
|
||||
chroma: false
|
||||
toc: true
|
||||
title: Debian
|
||||
description: All about ye ol' relaiable Debian Linux distribution!
|
||||
docs:
|
||||
- url: https://debian-handbook.info/browse/stable/
|
||||
name: Debian Administrator's Handbook
|
||||
description: Systems administration stuff relevant to Debian spesifically
|
||||
---
|
||||
|
||||
{{< img
|
||||
src="apprentice/debian/bouton.jpg"
|
||||
caption="The biggest of the official Debian button logos"
|
||||
hint=icon quality=100 >}}
|
||||
|
||||
<!-- Security? -->
|
||||
|
||||
Debian is a classic free and open source Linux distribution.
|
||||
It's one of the oldest Linux OSes and the basis of many other distros.
|
||||
Most notably Ubuntu.
|
||||
|
||||
Debian has three foundational documents.
|
||||
The [Debian Social Contract](https://www.debian.org/social_contract)/[OG Version](https://lists.debian.org/debian-announce/1997/msg00017.html),
|
||||
the [Debian Constitution](https://www.debian.org/devel/constitution) and
|
||||
the [Debian Free Software Guidelines](https://wiki.debian.org/DebianFreeSoftwareGuidelines).
|
||||
|
||||
Debian version code-names are famously named after characters from the [Toy Story](https://en.wikipedia.org/wiki/Toy_Story_(franchise)) films.
|
||||
It's unstable rolling release branch is named Sid, who in the Toy Stories regularly destroys his toys.
|
||||
|
||||
## Early History
|
||||
The first ever Debian release was on September 15th, 1993.
|
||||
It was an internal release of version 0.01.
|
||||
The first public release, version 0.90, included the "[Debian Linux Manifesto](https://www.debian.org/doc/manuals/project-history/manifesto.en.html)".
|
||||
That document outlining, the Debian founder, Ian Murdock's view for the Debian OS.
|
||||
Calling for Debian to become an openly maintained distribution, in the spirit of GNU/Linux.
|
||||
|
||||
During 1994 and 1995 Debian released 0.9x versions and was sponsored by the [Free Software Foundation](https://fsf.org).
|
||||
During this time Ian Murdock would delegate the base system and core package management to Bruce Perens, while Murdock focused on the management of the growing project.
|
||||
|
||||
{{< img
|
||||
src="apprentice/debian/button-1.gif"
|
||||
caption="The first Debian button logo by [Craig Small](mailto:csmall@debian.org)"
|
||||
hint=icon quality=100 >}}
|
||||
|
||||
In 1996 dpkg was already an essential part of Debian and Bruce Perens got the project leadership.
|
||||
He was a controversial leader and drafted the Debian Social Contract.
|
||||
During this time the Free Software Foundation would pull their sponsorship for the project.
|
||||
And Perens would go on to create the organization "[Software in the Public Interest](https://spi-inc.org)".
|
||||
He also wrote BusyBox to make it possible to have a Debian installer on a single floppy drive.
|
||||
|
||||
From 1999, the project leader was elected yearly.
|
||||
The number of applicants was overwhelming, and the project established the new member process.
|
||||
After this Debian slowly evolved into what it is today.
|
||||
|
||||
## Derivative works
|
||||
As of writing, Aug. 18th 2022, [DistroWatch](https://distrowatch.com) lists 118 active Debian based distros.
|
||||
And 404 also counting discontinued Debian based distros.
|
||||
Debian GNU/kFreeBSD only had one official stable port with the release of Debian 7.0 (Wheezy).
|
||||
That would of course be Debian with GNU user land utilities using the FreeBSD kernel.
|
||||
|
||||
{{< img
|
||||
src="apprentice/debian/devuan-logo.svg"
|
||||
title="Devuan logo"
|
||||
caption="A Debian fork not using systemd" >}}
|
||||
|
||||
And Debian GNU/Hurd using the GNU Hurd microkernel.
|
||||
It has been developed since 1998, but has never had an official Debian release.
|
||||
Still it's maintained and developed as an unofficial port.
|
||||
|
||||
In my opinion [Devuan](https://devuan.org) is one of the best Debian forks, but that may just be the systemd hate speaking.
|
||||
It has been mirroring Debian since 2017, but with systemd removed and sysvinit, runit or openrc as supported init system alternatives.
|
||||
|
||||
## Package management
|
||||
On Debian package management is done mainly through APT, the "Advanced Packaging Tool".
|
||||
Although there are loads of alternative methods and apt GUI frontends.
|
||||
APT uses dpkg under the hood, and this dpkg is the program responsible for managing all installed packages.
|
||||
As long as snap, flatpak, (home)brew or any other alternative package manager isn't installed beside it.
|
||||
Those examples however are often installed in conjunction with whatever package manager your distro of choice is.
|
||||
Because they install either in their own segregated environment.
|
||||
Or with all dependencies bundled and binaries that are statically linked.
|
||||
|
||||
The official Debian repos have several "areas" and only the free one is enabled by default.
|
||||
The DFSG/Debian Free Software Guidelines define what is and isn't free software in this context.
|
||||
But it's pretty trivial to add the *non-free* and *contrib* areas for installing official packages that may not be entirely free and open source.
|
||||
|
||||
The non-free contains packages that doesn't comply with the DFSG.
|
||||
And contrib contains packages that do comply, but fail other requirements, like depending on non-free packages.
|
||||
|
||||
## Branches
|
||||
There are three main branches, or as they may also be called suits or (sub?)distributions of Debain.
|
||||
These are *stable*, *testing* and *unstable*.
|
||||
*Unstable* has the latest and greatest software, but has no stability guarantees.
|
||||
After being barely tested in *unstable* packages are moved to *testing*.
|
||||
The *testing* branch gets "freezed" some time after a new Debian version.
|
||||
During this time the *testing* branch is, well, tested extensively to find bugs.
|
||||
Then they try and patch all the bugs to create the next major version.
|
||||
|
||||
Debian does have some other branches, like the *oldstable*, *oldoldstable* and *stapshot* branches.
|
||||
Oldstable is the previous major Debian branch.
|
||||
And oldoldstable is the one before that.
|
||||
The snapshot branches however are some other branch at some specific time.
|
||||
|
||||
{{< img
|
||||
src="apprentice/debian/hexagonal.png"
|
||||
tite="Hexagonal Debian swirl logo"
|
||||
caption="Also by [Elena Grandi](mailto:valhalla@trueelena.org), **sauce** may be found in the \"[Debian flyers repo](https://salsa.debian.org/debian/debian-flyers/tree/master/hexagonal-sticker)\""
|
||||
hint=icon >}}
|
||||
|
||||
As frozen branches usually only means features of packages are frozen.
|
||||
Of course security, performance and stability updates are applied.
|
||||
|
||||
## Branding
|
||||
The Debian "swirl" logo was made by Raul Silva in 1999 as part of a contest to replace the old semi-official logo that had been in use.
|
||||
It is said that the "swirl" represents [magic smoke](https://en.wikipedia.org/wiki/Magic_smoke)!
|
||||
Raul would win a @debian.org email address, and a set of Debian 2.1 CDs for the architecture of his choice.
|
||||
|
||||
One theory about the origin of the Debian logo is that [Buzz Lightyear](https://en.wikipedia.org/wiki/Buzz_Lightyear) not only has a little swirl on his chin.
|
||||
But the first Debian release was named after him.
|
||||
And [Stefano Zacchiroli](https://en.wikipedia.org/wiki/Stefano_Zacchiroli) who was the Debian leader from 2010 to 2013.
|
||||
Has suggested that Buzz's swirl is the Debian swirl.
|
||||
The other way around is a more likely candidate as Debian takes all their version code-names from [Toy Story](https://en.wikipedia.org/wiki/Toy_Story_(franchise)) characters.
|
||||
|
||||
{{< img
|
||||
src="apprentice/debian/diversity-2019.png"
|
||||
caption="Debian diversity logo by [Elena Grandi](mailto:valhalla@trueelena.org)"
|
||||
hint=icon >}}
|
||||
|
||||
## Features
|
||||
Debian is available in 75 languages with widely varying support.
|
||||
The installer itself is available in 76 languages.
|
||||
As of 2022 anyway.
|
||||
|
||||
Debian has several Linux flavors for each supported architecture.
|
||||
For example if running i386/32-bit you'd be able to use PAE ([Physical Address Extension](https://en.wikipedia.org/wiki/Physical_Address_Extension)) if the computer itself supports it.
|
||||
PAE lets a CPU use 64-bit memory addresses while otherwise running in a lower-bit mode.
|
||||
This is to be able to use more than 4 Gigabytes of RAM at once.
|
||||
|
||||
Debian officially only use open source software.
|
||||
But it's easy adding the "contrib" and "non-free" repository areas for installing stuff like the proprietary Nvidia drivers.
|
||||
|
||||
Debian has problems with built-in multimedia support as codecs are often threatened by patent infringements, are without source code or under too restrictive licenses.
|
||||
While you'd think all this stuff could just go in the "non-free" repository area.
|
||||
Software such as [libdvdcss](https://videolan.org/developers/libdvdcss.html) by [VideoLAN](https://videolan.org), the creators of [VLC Media Player](https://videolan.org/vlc/), is not hosted by Debian in their official repositories.
|
||||
|
||||
### A notable 3rd party repo
|
||||
A notable 3rd party repository is [deb-multimedia.org](https://deb-multimedia.org/), formerly debian-multimedia.org, providing software not present in official Debian repositories.
|
||||
Like Windows codecs, libdvdcss and the [Adobe Flash Player](https://en.wikipedia.org/wiki/Adobe_Flash_Player).
|
||||
The repository is maintained by [Christian Marillat](https://qa.debian.org/developer.php?login=marillat%40deb-multimedia.org) who is a Debian developer.
|
||||
But deb-multimedia is not part of Debian and is not hosted on Debian servers.
|
||||
|
||||
The deb-multimedia repository has packages already in official Debian repos, appraently interfearing with official maintenance.
|
||||
In 2012 this lead to [Stefano Zacchiroli](https://en.wikipedia.org/wiki/Stefano_Zacchiroli), the Debian leader at the time, would ask Marillat to either settle an agreement about the packaging or to stop using the Debian name.
|
||||
Mariallt chose the latter and debian-multimedia.org became deb-multimedia.org.
|
||||
This repo was so popular at the time that the name change and URL switch was announced on the official Debian blog.
|
||||
|
||||
## Development
|
||||
Each package has a maintainer which is either a single person or a team of people.
|
||||
The maintainer keeps track of changes to the packaged software, and ensures that the package coheres with the Debian Policy and quality standards.
|
||||
The packaged software often include modifications/patches to achieve this and even to fix non-Debian specific bugs.
|
||||
|
||||
All Debian maintainers have individual sets of OpenPGP key pairs used for digitally signing packages to be uploaded to the repositories.
|
||||
Newly uploaded packages' signatures are validated, and if valid, will be distributed to the hundreds of Debian repo mirrors all over the world daily.
|
||||
Debian developers are responsible for any package they upload even if the package was prepared by another contributor.
|
||||
|
||||
Initially a newly added package will only be available in the *unstable* branch.
|
||||
For a package to become a candidate for the next release, it must migrate to the *testing* branch by meeting several requirements.
|
||||
|
||||
1. Time in *unstable*, depending on change urgency.
|
||||
2. No "release-critical" bugs.
|
||||
3. No outdated versions in *unstable* for any release port/architecture.
|
||||
4. The migration does not break any package in *testing*.
|
||||
5. Its dependencies can be satisfied by packages already in *testing* or by packages being migrated at the same time.
|
||||
6. The migration is not blocked by a freeze.
|
||||
|
||||
This is all fine and dandy.
|
||||
But it happens that release-critical bugs pops up in shared libraries which many packages may depend on.
|
||||
This prevents those packages from entering *testing*, as we have to wait for the updated library to get updated first.
|
||||
However, this whole migration stuff happens twice a day, so shouldn't be much of a problem.
|
||||
This also renders *testing* a perpetual beta.
|
||||
|
||||
Sometimes the guidelines will be published for readying up for a new release.
|
||||
Then a freeze of *testing*, after everything is "reasonably up-to-date" and other significant issues are resolved.
|
||||
Then the *testing* branch becomes the new *stable*.
|
||||
|
||||
One version of a package may be in several branches at the same time.
|
||||
Usually *testing* and *unstable*, but if the same version of a package are keept between Debian releases.
|
||||
The same package on the same version may end up in *oldstable*, *stable*, *testing* and *unstable* at the same time.
|
||||
|
||||
One way many people bypass this whole setup is with cross distro package managers that sandbox applications.
|
||||
These would be package manager like flatpak, snap and brew.
|
||||
When using those for the packages one needs to keep on the latest versions.
|
||||
The developers of that/those applications can publish updated packages with the latest version continouesly.
|
||||
|
||||
New Debian versions are released approximately every 2 years.
|
||||
And will get support for about 3 years with updates for major security or usability fixes.
|
||||
Since Debian 3 (Squeeze) there has been a Debian LTS team that applies security updates after a Debian release has reached its end of life.
|
||||
Meaning a Debian release may now get up to 5 years of support in total.
|
||||
|
@ -1,64 +0,0 @@
|
||||
---
|
||||
date: 2022-08-18T03:10:27Z
|
||||
draft: false
|
||||
aliases: []
|
||||
categories: ['documentation', 'various']
|
||||
series: ['apprentice']
|
||||
tags: ['various', 'useful']
|
||||
chroma: true
|
||||
toc: true
|
||||
title: Linux Desktop Password Reset
|
||||
description: Simple guide to reset the password on Linux machines to which you have physical access to the disk.
|
||||
---
|
||||
|
||||
Hacking stuff is usually pretty trivial.
|
||||
As long as you've got physical access that is.
|
||||
And here I'll instruct you on how to reset passwords on a Linux installation.
|
||||
Either by booting a live ISO.
|
||||
Or by plugging the drive with the installation you'd like to reset some password(s) on into another Linux machine.
|
||||
|
||||
Realistically, repairing a broken installation is pretty similar.
|
||||
Although be aware that setting up the chroot may require additional steps.
|
||||
And actually fixing it would be harder than just running passwd in chroot on the installation.
|
||||
|
||||
## Setup
|
||||
For passwd we don't need any fancy setup, we just need the rootfs mounted, chroot into it and run passwd.
|
||||
Run "lsblk" to identify the disk you'll need to mount.
|
||||
Then mount it to /mnt.
|
||||
Some distros have software that can mount drives automatically to some media folder.
|
||||
This is fine for passwd, but for system repair operations you'd want to unmount that if it happens and do the whole setup manually.
|
||||
|
||||
For a system repair chroot setup use these additional mounts to make sure tools interacting with the system work.
|
||||
Assuming you mounted the rootfs and potentially the boot/EFI partition to /boot or /boot/efi.
|
||||
|
||||
{{< highlight sh >}}mount -R /dev /mnt/dev
|
||||
mount --make-rslave /mnt/dev
|
||||
mount -t proc proc /mnt/proc
|
||||
mount -t sysfs sysfs /mnt/sys
|
||||
mount -t tmpfs tmpfs /mnt/run
|
||||
{{< /highlight >}}
|
||||
|
||||
The options -R and -t for mount are short hands for \-\-rbind and \-\-types respectively.
|
||||
|
||||
## Fixing
|
||||
For doing the password reset or other operations on the installation other than simple file edits, you just chroot into the installation.
|
||||
|
||||
{{< highlight sh >}}chroot /mnt /bin/bash{{< /highlight >}}
|
||||
|
||||
You may also specify a new shell or one command with options to run in the new root after the path of the root.
|
||||
Also \-\-groups with group names and \-\-userspec with names or IDs of the main user and group to use during the chroot.
|
||||
Usually you'd want to just chroot using the root user.
|
||||
And to all the stuff you need to.
|
||||
|
||||
Like the password reset!
|
||||
|
||||
{{< highlight sh >}}passwd{{< /highlight >}}
|
||||
|
||||
And then exit the chroot shell and proceed with the cleanup before rebooting into the fixed installation.
|
||||
|
||||
{{< highlight sh >}}exit{{< /highlight >}}
|
||||
|
||||
## Cleanup
|
||||
Run "umount \-\-recursive" on the rootfs mount point as root.
|
||||
|
||||
{{< highlight sh >}}umount -R /mnt{{< /highlight >}}
|
@ -1,59 +1,12 @@
|
||||
---
|
||||
date: 2022-06-07T07:14:28Z
|
||||
draft: false
|
||||
draft: true
|
||||
aliases: []
|
||||
categories: ['documentation', 'networking']
|
||||
series: ['apprentice']
|
||||
tags: ['net', 'os']
|
||||
categories: ['various']
|
||||
series: []
|
||||
tags: ['various']
|
||||
toc: true
|
||||
title: Meraki
|
||||
description: Cisco Meraki basics and captive portal setup
|
||||
---
|
||||
|
||||
Meraki is Cisco's cloud managed networking solution.
|
||||
It has everything and more than what most people would need.
|
||||
But of course me being me, I don't like my infrastructure being managed by cloud services.
|
||||
|
||||
I did however work a little with Meraki at SkyLabs, and was pleasantly surprised.
|
||||
After having a couple very bad experiences with our Mikrotik setup script.
|
||||
Setting up a Meraki access point with our captive portal service was super easy!
|
||||
|
||||
## Captive portal setup
|
||||
As mentioned the captive portal setup on Meraki is relatively simple.
|
||||
And with a little luck the only 100% necessary configuration options would be just a "splash page URL" and RADIUS.
|
||||
And if the captive portal ain't responsible for authenticating people you could probably get away with just the splash page URL.
|
||||
But RADIUS is needed for actual captive portal authentication.
|
||||
|
||||
### Access control
|
||||
Even having a captive portal setup makes it incompatible with certain other options.
|
||||
And I think Meraki is a bit excessive with the limitations here.
|
||||
|
||||
##### Network access
|
||||
For the "Network access" you'd likely want it to be "Open", but if not.
|
||||
PSK, aka normal password is your only option for adding additional auth requirements.
|
||||
|
||||
##### Splash page
|
||||
Set security to; Sign-on with "my RADIUS server".
|
||||
|
||||
###### Advanced splash
|
||||
In here there are a few options you may want to change that changes the behavior of the captive portal hot-spot.
|
||||
Such as limiting users to being logged in with one device only.
|
||||
If users are allowed through if the box/access point can't connect to Meraki Cloud.
|
||||
The "Captive portal strength", this lets you allow non-HTTP traffic before captive portal login.
|
||||
And last, but definitely not least.
|
||||
The Walled garden, walled garden lets you have a list of allowed IPs that may be connected to before authorization.
|
||||
|
||||
##### RADIUS
|
||||
For RADIUS you'll need the IP and RADIUS secret for the server.
|
||||
Default RADIUS ports are 1812 for authentication and 1813 for RADIUS accounting.
|
||||
|
||||
### Other options
|
||||
There is also a separate Meraki dashboard page specific for "Splash page" options.
|
||||
In there you'd put your "Custom splash URL", although you may also manage a Meraki provided captive portal there.
|
||||
|
||||
## Caveats
|
||||
One thing that's kinda annoying about Meraki however is its RADIUS client.
|
||||
Meraki uses cloud based RADIUS clients, so from our side, we can only differentiate between them by the data that's sent.
|
||||
This has caused us to add some extra limitations on Meraki setups using our captive portals.
|
||||
Ain't too bad, but for RADIUS accounting to work it kinda gets ugly.
|
||||
And we would need RADIUS accounting for our paid SMS login.
|
||||
|
@ -1,104 +1,16 @@
|
||||
---
|
||||
date: 2022-06-08T10:34:42Z
|
||||
draft: false
|
||||
draft: true
|
||||
aliases: []
|
||||
categories: ['documentation', 'networking']
|
||||
series: ['apprentice']
|
||||
tags: ['net', 'os']
|
||||
categories: ['various']
|
||||
series: []
|
||||
tags: ['various']
|
||||
chroma: false
|
||||
toc: true
|
||||
title: Mikrotik
|
||||
description: Mikrotik routers has a lot of wired stuff builtin, here is some of that
|
||||
description: Mikrotik routers has a lot of wierd stuff builtin, here is some of that
|
||||
---
|
||||
|
||||
Mikrotik produces networking equipment and software.
|
||||
In 2021, they were the 3rd largest and first private company to reach a value above 1B EUR in their home country Latvia.
|
||||
|
||||
While their RouterOS has a terrible track record of getting hacked.
|
||||
It has a load of cool and useful features built right in.
|
||||
And all those ROS devices that constantly get hacked do so because of known vulnerabilities that would have been patched if only the devices where being updated on a regular basis.
|
||||
|
||||
## SkyLabs Mikrotik misadventures
|
||||
Since Mikrotiks are the most used and best supported equipment for our services.
|
||||
I got to work a lot with them when I wasn't programming or managing servers.
|
||||
So here is a collection of some problems I encountered along the way working with SkyLabs Mikrotik boxes.
|
||||
|
||||
### Status script
|
||||
The one story of me messing up big time as an apprentice is related to this piece of :poop: Mikrotik script.
|
||||
It works quite simple, it's supposed to run every 5 minutes, although I've seed boxes that used to run it every single minute until I came and updated the things.
|
||||
For each time it runs it collects all sorts of information about the box that runs it and then reports it to our API.
|
||||
|
||||
The thing that went wrong tho is a perfect example of how unpredictable simple changes can be.
|
||||
It was upgrading nginx from 1.18 to 1.22.
|
||||
That caused requests not properly URL encoded to get a 400 response.
|
||||
As you'd expect, right?
|
||||
But, as it turned out these status scripts on all the boxes didn't do so...
|
||||
And when all our servers run fail2ban it meant those boxes got IP banned.
|
||||
Causing the whole captive portal to stop working on those affected.
|
||||
|
||||
Interestingly a whole partners setup was fine, and the reason was a slight difference in the script.
|
||||
The way those boxes got their RouterOS version, it got just the number.
|
||||
While the standard version of the script also got the "branch", stable/long-term/beta.
|
||||
|
||||
I had two drafts of solution scripts so that we could upgrade nginx.
|
||||
The first one had an inline for loop that would URL encode the string for the URL path with all the parameters the script sends to the API.
|
||||
The other one just passed all the parameters in the HTTP body instead of the HTTP head of the request.
|
||||
Completely bypassing the need for URL encoding.
|
||||
|
||||
Of course the second option there is the best for several reasons.
|
||||
But the biggest one for us would have to be the fact that hotspot name is passed.
|
||||
And that would be user input.
|
||||
Never trust it.
|
||||
|
||||
### Full disk problem
|
||||
# Full disk problem
|
||||
The built-in drive on the boxes may get filled up by hidden files...
|
||||
There exists an official [fix_space.npk](https://www.mikrotik.com/download/share/fix_space.npk) package, but finding that was a little adventure in itself reading through old forum threads from 2018...
|
||||
I also managed to mess up a SkyLabs box using that package.
|
||||
Probably just because we did it remote.
|
||||
It's kinda funny, actually.
|
||||
That "fix_spacke.npk", if you look at it in a hex editor.
|
||||
You'll see that it's got a crazy amount of null bytes, and the most interesting.
|
||||
A bash script.
|
||||
|
||||
This whole problem actually happened to several SkyLabs managed Mikrotiks over the summer of 2022 as we needed to upgrade the SSL certificates on them.
|
||||
But with the disk full the new certificate would either not even get onto the disk of the boxes or corrupted as the whole certificated could not be written to the disk.
|
||||
In hindsight, I wonder how the guy updating the certs did it.
|
||||
As I've updated the status script on all boxes without issue.
|
||||
|
||||
## Sniff-sniff!
|
||||
The first Mikrotik "/tool/sniffer" pcap file I ever inspected was named "sniffsniff".
|
||||
I found it on a SkyLabs box, it's likely ancient and only had DHCP data if I remember correct.
|
||||
|
||||
But that's neither here nor there.
|
||||
|
||||
You see I got this interesting task after one of our customers wanted logging and blacklisting.
|
||||
This was after it was discovered on their end that somebody was using their guest network for hacking attempts.
|
||||
Specifically SQL injection against a bunch of servers, supposedly mostly Oracle and Amazon ones.
|
||||
|
||||
### Skrrting our efforts
|
||||
So for this I got to see for myself how powerful the Mikrotik sniffer tool actually is.
|
||||
The plan would be to use the built-in sniffer, find the mac of whoever is doing the naughty stuff.
|
||||
And then just blacklist by MAC.
|
||||
Any hacker should be able to just use bogus macs tho.
|
||||
And if they're extra clever they might even impersonate legitimate users.
|
||||
That would for sure mess up our blocking efforts big time.
|
||||
If you ask me the only solution then would be to require captive portal authentication with SMS code.
|
||||
Or some other one where you have to put in some personal info.
|
||||
|
||||
### Implementation
|
||||
Mikrotik routers or anything running RouterOS have that built-in /tool/sniffer thing.
|
||||
It can directly output pcap files to a disk, but it also has a streaming option.
|
||||
But that stream would be using a protocol called [TZSP](https://en.wikipedia.org/wiki/TZSP) or TaZmen Sniffer Protocol.
|
||||
So I found a neat open source tool written in C called "[tzsp2pcap](https://github.com/thefloweringash/tzsp2pcap)".
|
||||
It does exactly as the name would imply.
|
||||
You may read my little guide on it [here](../tzsp2pcap).
|
||||
|
||||
So for the capture setup I used this streaming option, so we could store a bunch more packets than directly on the box.
|
||||
After fiddling around with the filtering options of the /tool/sniffer I ran the tzsp2pcap with screen on our production VPN server with options to write to a new file whenever the current file would reach 1 GB.
|
||||
Then I just manually moved them to my work computer and the backup server.
|
||||
If this were going to continue, I'd make some script to automagically move stuff and run that with a cron job once or twice a week.
|
||||
|
||||
### Conclusion
|
||||
I ran the thing over a weekend and then some, but it was all useless.
|
||||
As the customer in question wanted to resign our services the Monday after we started sniffing...
|
||||
Was still a fun learning experience tho.
|
||||
And I got to use Wireshark during work! :grin:
|
||||
There exists an official [fix_space](https://www.mikrotik.com/download/share/fix_space.npk) package, but finding that was a little adventure in itself reading through old forum threads from 2018...
|
||||
|
@ -73,8 +73,12 @@ It's even been used as a Wi-Fi password.
|
||||
To fix this one very easily I just enabled 2FA on the account.
|
||||
But the whole account should probably just be deleted as nobody ever uses it.
|
||||
|
||||
{{< raw >}}
|
||||
<!-- You cheecky bastard! -->
|
||||
{{< /raw >}}
|
||||
<!--
|
||||
## Servers
|
||||
{{< img src="apprentice/skyid/old-intrauser-key.png" caption="The old intrauser ssh key" hint=text >}}
|
||||
{{< img src="apprentice/skyid/old-intrauser-key.png" caption="The old intrauser ssh key" >}}
|
||||
|
||||
On the other side, the cloud servers had some bigger problems.
|
||||
Here I did find a *BIG* security issue. Ancient ssh keys.
|
||||
@ -91,7 +95,7 @@ And the thing is, [gtfobins](https://gtfobins.github.io/) has a privilege escala
|
||||
|
||||
So check it; these screenshots are from SkyLabs' Ansible git log!~
|
||||
|
||||
{{< img src="apprentice/skyid/intrauser-key.png" caption="Me finally updating the key" hint=text >}}
|
||||
{{< img src="apprentice/skyid/intrauser-key.png" caption="Me finally updating the key" >}}
|
||||
|
||||
And it's even worse... as it turns out the OpenVPN setup also has keys from guess when!
|
||||
That's right! 2016...
|
||||
@ -102,3 +106,7 @@ To be honest I'm quite surprised the servers hasn't been pwnd big time!
|
||||
As I've in fact proven that any ex-employee that has a copy of our Ansible repo could easily forge OpenVPN client keys and certificates.
|
||||
And also got full root access over ssh anyway.
|
||||
Just add a little [Tor](https://torproject.org/) magic on top of that, and you got full access to all the servers without us being able to trace it back...
|
||||
-->
|
||||
{{< raw >}}
|
||||
<!-- Grep my github.io repo for secrets located here! -->
|
||||
{{< /raw >}}
|
||||
|
@ -1,45 +0,0 @@
|
||||
---
|
||||
date: 2022-08-18T09:57:34Z
|
||||
draft: false
|
||||
aliases: []
|
||||
categories: ['documentation', 'networking']
|
||||
series: ['apprentice']
|
||||
tags: ['net', 'os']
|
||||
chroma: true
|
||||
toc: true
|
||||
title: Tzsp2pcap
|
||||
description: TaZmen Sniffer Protocol to Packet CAPture utility program.
|
||||
git:
|
||||
name: thefloweringash/tzsp2pcap
|
||||
url: https://github.com/thefloweringash/tzsp2pcap
|
||||
---
|
||||
|
||||
This is a very useful tool when working with Mikrotiks.
|
||||
As their built-in sniffer tool has support for TZSP (TaZmen Sniffer Protocol) streaming.
|
||||
This will send all packets that match the filtering options to some destination over TZSP/UDP.
|
||||
|
||||
This destination may be some machine running this tzsp2pcap.
|
||||
Allowing you to get a pcap remotely from a Mikrtoik without touching the Mikrotiks disk.
|
||||
This is super useful if the box has traffic as the Mikrotik routers usually has a disk with a size in megabytes.
|
||||
|
||||
## Using tzsp2pcap
|
||||
The program has all the options it should.
|
||||
|
||||
Allowing you to specify listening port, output file, receive buffer size, output file rotation and some more.
|
||||
|
||||
{{< highlight sh >}}# tzsp2pcap -h
|
||||
|
||||
tzsp2pcap: receive tazmen sniffer protocol over udp and
|
||||
produce pcap formatted output
|
||||
|
||||
Usage tzsp2pcap [-h] [-v] [-f] [-p PORT] [-o FILENAME] [-s SIZE] [-G SECONDS] [-C SIZE] [-z CMD]
|
||||
-h Display this message
|
||||
-v Verbose (repeat to increase up to -vv)
|
||||
-f Flush output after every packet
|
||||
-p PORT Specify port to listen on (defaults to 37008)
|
||||
-o FILENAME Write output to FILENAME (defaults to stdout)
|
||||
-s SIZE Receive buffer size (defaults to 65535)
|
||||
-G SECONDS Rotate file every n seconds
|
||||
-C FILESIZE Rotate file when FILESIZE is reached
|
||||
-z CMD Post-rotate command to execute
|
||||
{{< /highlight >}}
|
@ -49,5 +49,5 @@ Then it's up to the hosting provider to configure the web server and potentially
|
||||
Nginx site for hardened WordPress;
|
||||
{{< highlight nginx >}}{{% asset "apprentice/wordpress/nginx.conf" %}}{{< /highlight >}}
|
||||
|
||||
Apache/LiteSpeed virtual host directives for a simillar setup;
|
||||
Apache virtual host directives for a simillar setup;
|
||||
{{< highlight aconf >}}{{% asset "apprentice/wordpress/apache.conf" %}}{{< /highlight >}}
|
||||
|
@ -1,34 +0,0 @@
|
||||
---
|
||||
date: 2022-12-15T15:10:59Z
|
||||
aliases: []
|
||||
categories: ['captive-portals', 'various']
|
||||
series: ['apple']
|
||||
tags: ['various', 'apple']
|
||||
chroma: false
|
||||
toc: true
|
||||
title: Apple CNA (Captive Network Assistant)
|
||||
description: The Apple "Captive Network Assistant" is some software running on Apple devices that checks if Wi-Fi networks have captive portal setups and potentially starts a sand-boxed browser to do the portal login.
|
||||
---
|
||||
|
||||
Now I may be biased as I've had to work with captive portals and been annoyed by Apples sand-boxed captive network assistants web browser.
|
||||
Apples CNA sandbox browser does not allow any sort of persistent storage on the device.
|
||||
To the point where localStorage is outright disallowed and cookies are not stored between sessions.
|
||||
It's also not allowed to open new windows/tabs as the browser only has the one window you get and won't allow any attempts to get out of the sandbox by opening a new window or open some app.
|
||||
|
||||
What's very curious however is the fact that most stack overflow questions about the Apples captive portal browser is about using Facebook as the authentication method which we ([Sky Labs](https://skylabs.no)) have had for a long time.
|
||||
But where I finally had to face this pice of :poop: was with the Norwegian payment service called [Vipps](https://vipps.no).
|
||||
For anyone not in the loop Vipps is like Norwegian Venmo/CashApp.
|
||||
Although the whole selling point of Vipps is its "instant" payments.
|
||||
|
||||
The one single limitation of Apples CNA sandbox browser that throws a gigantic wrench into our Vipps integration is no opening of app links.
|
||||
This causes it to be pretty finicky to login on the same device as one is trying to pay with.
|
||||
So we expect end-users to get very annoyed and confused by this.
|
||||
|
||||
One alternative to get the users out of the sandbox browser is to preemptively give them full network access and send them to their normal browser to do the payment.
|
||||
But we want to avoid that option as it would require RADIUS CoA (Change of Authorization) to be working for us to be able to kick out users that starts the payment process, but doesn't complete it.
|
||||
And we're already having issues around this with our paid SMS authentication method.
|
||||
|
||||
If we're lucky enough to have Vipps help us, they could probably make it so that the app always send the user to our specified web page after payment.
|
||||
Not just when waiting on the Vipps webpage for payment on another device or after having the app opened from an app link.
|
||||
|
||||
<!-- This tomfoolery -->
|
@ -1,10 +1,10 @@
|
||||
---
|
||||
date: 2022-06-07T22:11:49Z
|
||||
draft: false
|
||||
aliases: []
|
||||
categories: ['exploit']
|
||||
series: ['hacking']
|
||||
tags: ['bug']
|
||||
patched: true
|
||||
chroma: false
|
||||
toc: true
|
||||
title: Duolingo Xp Exploit
|
||||
|
@ -1,38 +0,0 @@
|
||||
---
|
||||
date: 2022-08-22T14:21:06Z
|
||||
draft: false
|
||||
aliases: []
|
||||
categories: ['exploit']
|
||||
series: ['hacking']
|
||||
tags: ['bug']
|
||||
patched: true
|
||||
chroma: false
|
||||
toc: true
|
||||
title: Duolingo Xp Exploit
|
||||
description: Jeg fant en bug i Duoling appen for iOS som lar brukere med super/pro øyeblikkelig fullføre en snakke trening.
|
||||
---
|
||||
|
||||
{{< raw >}}
|
||||
<style>video { float: right; }</style>
|
||||
<video width='27%' autoplay controls loop muted>
|
||||
<source src='/duolingo-xp-exploit.mp4' type='video/mp4'>
|
||||
<b>Nettleseren din støtter ikke video taggen!</b>
|
||||
</video>
|
||||
{{< /raw >}}
|
||||
|
||||
Det er mulig for brukere med super/pro å øyeblikkelig fullføre snakke trenginger på iOS.
|
||||
|
||||
## Hvordan reprodusere
|
||||
|
||||
1. Pass på at Duolingo appen *ikke* har mikrofon tilgang.
|
||||
2. Start en rude "Perfect Pronounciation" under "Practrice Hub".
|
||||
3. Trykk fortsett og når du blir bedt om å gi mikrofon tilgang, bare klikk avbryt.
|
||||
4. Profit. (Øyeblikkelig perfekt leksjon!)
|
||||
|
||||
## Oppsummering
|
||||
Buggen her er tilsynelatende det faktum at appens første spørsmål om mikrofon tilgang ikke egentlig gjør noe annet enn å *be* om mikrofon tilgang.
|
||||
Senere får vi faktisk opp en melding om mikrofon tilgang som kan ta sluttbrukeren til innstillingene.
|
||||
Duoling appen skipper alle snakke/lytte spørsmål i en leksjon når du trykker knappen om at du ikke kan nå.
|
||||
Men dette er selvfølgelig et stort problem når alle spørsmålene er av disse typene.
|
||||
|
||||
Sluttresultatet er en *nesten* øyeblikkelig perfekt leksjon!~
|
@ -1,27 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang='{{ .Language.Lang }}'>
|
||||
<html lang='en'>
|
||||
<head>
|
||||
<meta charset='UTF-8'>
|
||||
<meta name='robots' content='index,follow'>
|
||||
{{ if isset .Params "title" }}
|
||||
<title>{{ site.Title }} - {{ .Title }}</title>
|
||||
{{ else }}
|
||||
<title>{{ site.Title }}</title>
|
||||
{{ with resources.Get "favicon.ico" | resources.Fingerprint }}
|
||||
<link rel='icon' href='{{ .RelPermalink }}' integrity='{{ .Data.Integrity }}' />
|
||||
{{ end }}
|
||||
{{ if .Description }}
|
||||
<meta name='description' content='{{ .Description }}'>
|
||||
{{ end }}
|
||||
{{ with resources.Get "favicon.png" }}
|
||||
{{ with . | fingerprint }}
|
||||
<link rel='icon' href='{{ .RelPermalink }}' integrity='{{ .Data.Integrity }}' />
|
||||
{{ end }}
|
||||
{{ with .Resize "192x192 png" | fingerprint }}
|
||||
<link rel="apple-touch-icon" href="{{ .RelPermalink }}" integrity='{{ .Data.Integrity }}' />
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
<meta name='viewport' content='width=device-width,initial-scale=1.0'>
|
||||
<meta name="theme-color" content="#00FF00" />
|
||||
{{ block "meta" . }}
|
||||
<meta name='viewport' content='width=device-width,initial-scale=1.0'>
|
||||
{{ end }}
|
||||
<meta name='twitter:card' content='summary'>
|
||||
<meta property='og:title' content='{{ site.Title }}' />
|
||||
@ -33,6 +19,14 @@
|
||||
{{ printf `<link rel='%s' type='%s' href='%s' title='%s' />` .Rel .MediaType.Type .Permalink $.Site.Title | safeHTML }}
|
||||
{{ end -}}
|
||||
<link rel='stylesheet' href='https://stackpath.bootstrapcdn.com/bootstrap/4.5.1/css/bootstrap.min.css' crossorigin='anonymous'>
|
||||
{{ if isset .Params "title" }}
|
||||
<title>{{ site.Title }} - {{ .Title }}</title>
|
||||
{{ else }}
|
||||
<title>{{ site.Title }}</title>
|
||||
{{ end }}
|
||||
{{ if .Description }}
|
||||
<meta name='description' content='{{ .Description }}'>
|
||||
{{ end }}
|
||||
{{ block "head" . }}{{ end }}
|
||||
{{ if .Param "chroma" }}
|
||||
{{ with resources.Get "chroma.scss" | toCSS | minify | fingerprint | resources.PostProcess }}
|
||||
@ -42,7 +36,6 @@
|
||||
{{ with resources.Get "main.scss" | toCSS | minify | fingerprint | resources.PostProcess }}
|
||||
<link href='{{ .RelPermalink }}' integrity="{{ .Data.Integrity }}" rel='stylesheet'>
|
||||
{{ end }}
|
||||
<script defer data-domain="io.sivert.pw" src="https://anal.42069.no/js/script.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
@ -69,4 +62,4 @@
|
||||
</footer>
|
||||
</body>
|
||||
{{ block "bottom" . }}{{ end }}
|
||||
</html>
|
||||
</html>
|
@ -9,9 +9,8 @@
|
||||
<h3>Posts</h3>
|
||||
<ul class='contents'>
|
||||
{{ range .Pages }}
|
||||
<li><a href='{{ .RelPermalink }}'>
|
||||
{{ partial "summary.html" . }}
|
||||
</a></li>
|
||||
<br />
|
||||
<a href='{{ .RelPermalink }}'><li>{{ partial "summary.html" . }}</li></a>
|
||||
{{ end }}
|
||||
</ul>
|
||||
{{ end }}
|
||||
|
@ -6,9 +6,10 @@
|
||||
{{ .Content }}
|
||||
<ul class='contents'>
|
||||
{{ range .Pages }}
|
||||
<li><a href='{{ .RelPermalink }}'>
|
||||
{{ partial "summary.html" . }}
|
||||
</a></li>
|
||||
<br />
|
||||
<a href='{{ .RelPermalink }}'>
|
||||
<li>{{ partial "summary.html" . }}</li>
|
||||
</a>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</article>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<center>
|
||||
<div class='footer-content'>
|
||||
<p>2020 - {{ (now.AddDate 0 1 0).Format "2006" }} ©{{ with .Site.Author }} {{ .name }}{{ end }}</p>
|
||||
<p>2020 - {{ now.Format "2006" }} ©{{ with .Site.Author }} {{ .name }}{{ end }}</p>
|
||||
</div>
|
||||
<!-- <div class='footer-social'>
|
||||
<a href='#' class='icons'><img src='/facebook-icon.svg'></a>
|
||||
|
@ -3,15 +3,13 @@
|
||||
<li class='{{ if $currentPage.HasMenuCurrent "main" . }}active{{ end }}'>
|
||||
<a href='#'>{{ .Pre }}<span>{{ .Name }}</span></a>
|
||||
</li>
|
||||
<li>
|
||||
<ul class='sub-menu'>
|
||||
{{ range .Children }}
|
||||
<li class='{{ if $currentPage.IsMenuCurrent "main" . }}active{{ end }}'>
|
||||
<a href='{{ .URL }}'>{{ .Name }}</a>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
</li>
|
||||
<ul class='sub-menu'>
|
||||
{{ range .Children }}
|
||||
<li class='{{ if $currentPage.IsMenuCurrent "main" . }}active{{ end }}'>
|
||||
<a href='{{ .URL }}'>{{ .Name }}</a>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
{{ else }}
|
||||
<li>
|
||||
<a href='{{ .URL }}'>
|
||||
|
@ -8,8 +8,7 @@
|
||||
{{ range .Site.Menus.left }}
|
||||
{{ partial "menu" . }}
|
||||
{{ end }}
|
||||
<li id='right'>
|
||||
<ul>
|
||||
<div class='link-group'>
|
||||
{{ range .Site.Menus.main }}
|
||||
{{ partial "menu" . }}
|
||||
{{ end }}
|
||||
@ -17,7 +16,6 @@
|
||||
<img class='icons' src='/search-icon.svg'>
|
||||
</a>
|
||||
</li> -->
|
||||
</ul>
|
||||
</li>
|
||||
</div>
|
||||
</ul>
|
||||
</nav>
|
@ -1,11 +1,13 @@
|
||||
{{- $pubdate := .PublishDate.Format "02/01/2006" }}
|
||||
{{- $lastmod := .Lastmod.Format "02/01/2006" }}
|
||||
<article>
|
||||
<p class="heading">{{ .Title }}</p>
|
||||
{{ i18n "published" }} {{ $pubdate }}
|
||||
{{ if ne $pubdate $lastmod }}
|
||||
{{ i18n "modified" }} {{ $lastmod }}
|
||||
{{ end }}<br />
|
||||
{{ .Summary }}
|
||||
{{ if .Truncated }}{{ i18n "readMore" }}...{{ end }}
|
||||
<div>
|
||||
<h3>{{ .Title }}</h3>
|
||||
{{ i18n "published" }} {{ $pubdate }}
|
||||
{{ if ne $pubdate $lastmod }}
|
||||
{{ i18n "modified" }} {{ $lastmod }}
|
||||
{{ end }}<br />
|
||||
{{ .Summary }}
|
||||
{{ if .Truncated }}{{ i18n "readMore" }}...{{ end }}
|
||||
</div>
|
||||
</article>
|
@ -1,16 +1,10 @@
|
||||
<aside id='meta'>
|
||||
<header>
|
||||
<h4>{{ or (.Param "tit") .Title }}</h4>
|
||||
{{ if .Param "patched" }}
|
||||
<p><b style="color: brightgreen">PATCHED</b></p>
|
||||
{{ end }}
|
||||
<p>
|
||||
{{ i18n "wordCount" .WordCount }}.
|
||||
{{ i18n "readingTime" .ReadingTime }}.
|
||||
</p>
|
||||
<p>
|
||||
{{ .Param "description" }}
|
||||
</p>
|
||||
</header>
|
||||
{{ if .Param "docs" }}
|
||||
<h5>Documentation:</h5>
|
||||
@ -35,4 +29,4 @@
|
||||
{{ end }}
|
||||
</ul>
|
||||
{{ end }}
|
||||
</aside>
|
||||
</aside>
|
@ -1,31 +1,6 @@
|
||||
{{ $img := resources.Get (.Get "src") }}
|
||||
{{ $hint := "photo" }}
|
||||
{{ $q := 69 }}
|
||||
{{ if (.Get "quality" )}}
|
||||
{{ $q = .Get "quality" }}
|
||||
{{ end }}
|
||||
{{ if (.Get "hint" )}}
|
||||
{{ $hint = .Get "hint" }}
|
||||
{{ end }}
|
||||
|
||||
{{ if ne $img.MediaType.SubType "svg" }}
|
||||
{{ $w := "" }}
|
||||
{{ $h := "" }}
|
||||
|
||||
{{ if (.Get "width") }}
|
||||
{{ $w = .Get "width" }}
|
||||
{{ else }}
|
||||
{{ $w = $img.Width | string }}
|
||||
{{ end }}
|
||||
{{ if (.Get "height") }}
|
||||
{{ $h = .Get "height" }}
|
||||
{{ end }}
|
||||
|
||||
{{ $img = $img.Resize (printf "%sx%s webp %s q%d" $w $h $hint $q) }}
|
||||
{{ end }}
|
||||
|
||||
<figure {{ with .Get "class" }}class='{{.}}'{{ end }}>
|
||||
{{ with $img | fingerprint }}
|
||||
{{ with $img.Resize (printf "%dx webp q69" $img.Width) | fingerprint }}
|
||||
<a href='{{ with $.Get "link" }}{{ . }}{{ else }}{{ .RelPermalink }}{{ end }}' target='_blank'>
|
||||
<img src='{{ .RelPermalink }}' integrity='{{ .Data.Integrity }}'
|
||||
{{ if or ($.Get "alt") ($.Get "caption") }}alt='{{ with $.Get "alt" }}{{ . }}
|
||||
@ -36,7 +11,7 @@
|
||||
<figcaption>{{ if isset .Params "title" }}
|
||||
<h4>{{ .Get "title" }}</h4>{{ end }}
|
||||
{{ if or (.Get "caption") (.Get "attr") }}<p>
|
||||
{{ .Get "caption" | markdownify }}
|
||||
{{ .Get "caption" }}
|
||||
{{ with .Get "attrlink" }}<a href="{{ . }}"> {{ end }}
|
||||
{{ .Get "attr" }}
|
||||
{{ if .Get "attrlink" }}</a> {{ end }}
|
||||
|