diff options
52 files changed, 2302 insertions, 440 deletions
| @@ -0,0 +1 @@ | |||
| static/agpl-3.0.txt \ No newline at end of file | |||
diff --git a/archetypes/default.md b/archetypes/default.md deleted file mode 100644 index c6f3fce..0000000 --- a/archetypes/default.md +++ /dev/null | |||
| @@ -1,5 +0,0 @@ | |||
| 1 | +++ | ||
| 2 | title = '{{ replace .File.ContentBaseName "-" " " | title }}' | ||
| 3 | date = {{ .Date }} | ||
| 4 | draft = true | ||
| 5 | +++ | ||
diff --git a/assets/main.scss b/assets/main.scss deleted file mode 100644 index cea2e5e..0000000 --- a/assets/main.scss +++ /dev/null | |||
| @@ -1,248 +0,0 @@ | |||
| 1 | $background: #0e0c06; | ||
| 2 | $foreground: #d4b782; | ||
| 3 | $black: #1b1918; | ||
| 4 | $brblack: #544b44; | ||
| 5 | $red: #d42215; | ||
| 6 | $green: #358c15; | ||
| 7 | $yellow: #9a6200; | ||
| 8 | $blue: #00458d; | ||
| 9 | $magenta: #773dbf; | ||
| 10 | $cyan: #008a7b; | ||
| 11 | $white: #cfb688; | ||
| 12 | |||
| 13 | html { | ||
| 14 | font-family: sans-serif; | ||
| 15 | color: $foreground; | ||
| 16 | background-color: $background; | ||
| 17 | } | ||
| 18 | |||
| 19 | body { | ||
| 20 | max-width: 920px; | ||
| 21 | margin: 0 auto; | ||
| 22 | padding: 1rem; | ||
| 23 | font-family: monospace; | ||
| 24 | } | ||
| 25 | |||
| 26 | h1 { | ||
| 27 | margin-top: 0; | ||
| 28 | font-size: 1.5rem; | ||
| 29 | |||
| 30 | small { | ||
| 31 | display: block; | ||
| 32 | font-size: 1rem; | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | a { | ||
| 37 | color: $yellow; | ||
| 38 | text-decoration: none; | ||
| 39 | } | ||
| 40 | |||
| 41 | a:hover { | ||
| 42 | color: $yellow; | ||
| 43 | text-decoration: underline; | ||
| 44 | } | ||
| 45 | |||
| 46 | a:visited { | ||
| 47 | color: $green; | ||
| 48 | } | ||
| 49 | |||
| 50 | .index { | ||
| 51 | display: flex; | ||
| 52 | flex-direction: row; | ||
| 53 | |||
| 54 | .article-list { | ||
| 55 | flex-grow: 1; | ||
| 56 | margin: auto; | ||
| 57 | max-width: 600px; | ||
| 58 | |||
| 59 | .article { | ||
| 60 | margin-bottom: 1rem; | ||
| 61 | } | ||
| 62 | |||
| 63 | .date { | ||
| 64 | display: block; | ||
| 65 | color: $brblack; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | aside { | ||
| 70 | width: 40%; | ||
| 71 | |||
| 72 | img { | ||
| 73 | display: block; | ||
| 74 | margin: 0 auto 1rem; | ||
| 75 | border-radius: 5px; | ||
| 76 | } | ||
| 77 | |||
| 78 | dt { | ||
| 79 | font-size: 0.9rem; | ||
| 80 | } | ||
| 81 | |||
| 82 | dd { | ||
| 83 | margin-left: 0; | ||
| 84 | |||
| 85 | &:not(:last-child) { | ||
| 86 | margin-bottom: 0.5rem; | ||
| 87 | } | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | @media(max-width: 640px) { | ||
| 92 | aside { | ||
| 93 | display: none; | ||
| 94 | } | ||
| 95 | } | ||
| 96 | } | ||
| 97 | |||
| 98 | article { | ||
| 99 | margin: 0 auto; | ||
| 100 | max-width: 720px; | ||
| 101 | line-height: 1.3; | ||
| 102 | |||
| 103 | img, video, iframe { | ||
| 104 | // !important for asciinema frames | ||
| 105 | display: block !important; | ||
| 106 | margin: 0 auto !important; | ||
| 107 | max-width: 90%; | ||
| 108 | |||
| 109 | @media(max-width: 640px) { | ||
| 110 | max-width: calc(100% - 2rem); | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 114 | .comment { | ||
| 115 | margin: 2rem auto 0; | ||
| 116 | max-width: 80%; | ||
| 117 | color: #333; | ||
| 118 | } | ||
| 119 | } | ||
| 120 | |||
| 121 | .footnotes { | ||
| 122 | font-size: 0.85rem; | ||
| 123 | } | ||
| 124 | |||
| 125 | footer { | ||
| 126 | margin-top: 2rem; | ||
| 127 | text-align: center; | ||
| 128 | font-size: 0.8rem; | ||
| 129 | color: #333; | ||
| 130 | } | ||
| 131 | |||
| 132 | .float-img { | ||
| 133 | float: right; | ||
| 134 | display: inline; | ||
| 135 | padding-left: 1rem; | ||
| 136 | |||
| 137 | @media(max-width: 640px) { | ||
| 138 | display: block; | ||
| 139 | float: none; | ||
| 140 | padding-left: inherit; | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | pre { | ||
| 145 | background-color: $black; | ||
| 146 | padding: 0.25rem 1rem; | ||
| 147 | margin: 0 -1rem; | ||
| 148 | max-width: 100%; | ||
| 149 | overflow-x: auto; | ||
| 150 | |||
| 151 | .cp { | ||
| 152 | color: #800; | ||
| 153 | } | ||
| 154 | |||
| 155 | .k { | ||
| 156 | color: #008; | ||
| 157 | } | ||
| 158 | |||
| 159 | .kt, .kd, .kc { | ||
| 160 | color: #44F; | ||
| 161 | } | ||
| 162 | |||
| 163 | .s { | ||
| 164 | color: #484; | ||
| 165 | font-style: italic; | ||
| 166 | } | ||
| 167 | |||
| 168 | .cm, .c1 { | ||
| 169 | color: #333; | ||
| 170 | font-style: italic; | ||
| 171 | } | ||
| 172 | |||
| 173 | .gi { | ||
| 174 | color: $green; | ||
| 175 | } | ||
| 176 | |||
| 177 | .gd { | ||
| 178 | color: $red; | ||
| 179 | } | ||
| 180 | |||
| 181 | .gu { | ||
| 182 | color: $blue; | ||
| 183 | } | ||
| 184 | } | ||
| 185 | |||
| 186 | summary { | ||
| 187 | cursor: pointer; | ||
| 188 | background-color: $black; | ||
| 189 | padding: 0.25rem 1rem; | ||
| 190 | margin: 0 -1rem; | ||
| 191 | } | ||
| 192 | |||
| 193 | details[open] { | ||
| 194 | border-bottom: 1rem solid $black; | ||
| 195 | margin: 0 -1rem 1rem; | ||
| 196 | padding: 0 1rem; | ||
| 197 | } | ||
| 198 | |||
| 199 | .text-center { | ||
| 200 | text-align: center; | ||
| 201 | } | ||
| 202 | |||
| 203 | blockquote { | ||
| 204 | border-left: 5px solid #bbb; | ||
| 205 | background-color: $black; | ||
| 206 | padding: 0 1rem; | ||
| 207 | margin-left: calc(-1rem - 5px); | ||
| 208 | margin-right: -1rem; | ||
| 209 | |||
| 210 | blockquote { | ||
| 211 | margin-right: 0; | ||
| 212 | margin-left: 0; | ||
| 213 | } | ||
| 214 | } | ||
| 215 | |||
| 216 | dl { | ||
| 217 | display: grid; | ||
| 218 | grid-template-columns: auto 1fr; | ||
| 219 | grid-gap: 0.2rem 1rem; | ||
| 220 | |||
| 221 | dt { | ||
| 222 | font-weight: bold; | ||
| 223 | grid-column-start: 1; | ||
| 224 | } | ||
| 225 | |||
| 226 | dd { | ||
| 227 | grid-column-start: 2; | ||
| 228 | margin: 0; | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | .alert { | ||
| 233 | padding: 0.5rem; | ||
| 234 | border: 1px solid transparent; | ||
| 235 | margin-bottom: 1rem; | ||
| 236 | |||
| 237 | &.alert-danger { | ||
| 238 | background: #f8d7da; | ||
| 239 | color: #721c24; | ||
| 240 | border-color: #f5c6cb; | ||
| 241 | } | ||
| 242 | |||
| 243 | &.alert-info { | ||
| 244 | background: #d1ecf1; | ||
| 245 | color: #0c5460; | ||
| 246 | border-color: #bee5eb; | ||
| 247 | } | ||
| 248 | } | ||
diff --git a/content/_index.html b/content/_index.html deleted file mode 100644 index 2f84b49..0000000 --- a/content/_index.html +++ /dev/null | |||
| @@ -1,3 +0,0 @@ | |||
| 1 | --- | ||
| 2 | title: Vineet's site | ||
| 3 | --- | ||
diff --git a/haunt.scm b/haunt.scm new file mode 100644 index 0000000..b6d799a --- /dev/null +++ b/haunt.scm | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | (use-modules (haunt asset) | ||
| 2 | (haunt builder blog) | ||
| 3 | (haunt builder atom) | ||
| 4 | (haunt builder assets) | ||
| 5 | (haunt reader commonmark) | ||
| 6 | (haunt publisher rsync) | ||
| 7 | (haunt post) | ||
| 8 | (haunt site) | ||
| 9 | (theme)) | ||
| 10 | |||
| 11 | (site #:title "Vineet's site" | ||
| 12 | #:domain "vineetk.net" | ||
| 13 | #:default-metadata | ||
| 14 | '((author . "Vineet K") | ||
| 15 | (email . "me@vineetk.net")) | ||
| 16 | #:readers (list commonmark-reader) | ||
| 17 | #:builders (list (blog #:theme vin-theme | ||
| 18 | #:collections | ||
| 19 | `(("Posts" "index.html" ,posts/reverse-chronological))) | ||
| 20 | (atom-feed) | ||
| 21 | (static-directory "images") | ||
| 22 | (static-directory "static")) | ||
| 23 | #:publishers (list (rsync-publisher #:destination "/var/www/vineetk_html/" | ||
| 24 | #:user "vin" | ||
| 25 | #:host "saklas"))) | ||
diff --git a/images/bctf23_electronical-mountain_aes.png b/images/bctf23_electronical-mountain_aes.png new file mode 100644 index 0000000..2349e95 --- /dev/null +++ b/images/bctf23_electronical-mountain_aes.png | |||
| Binary files differ | |||
diff --git a/images/bctf23_electronical-tux_aes.png b/images/bctf23_electronical-tux_aes.png new file mode 100644 index 0000000..0c0e0f8 --- /dev/null +++ b/images/bctf23_electronical-tux_aes.png | |||
| Binary files differ | |||
diff --git a/images/crewctf24_sniff/breadboard.jpg b/images/crewctf24_sniff/breadboard.jpg new file mode 100644 index 0000000..63ce2b7 --- /dev/null +++ b/images/crewctf24_sniff/breadboard.jpg | |||
| Binary files differ | |||
diff --git a/images/crewctf24_sniff/converted_eink_image.png b/images/crewctf24_sniff/converted_eink_image.png new file mode 100644 index 0000000..d017563 --- /dev/null +++ b/images/crewctf24_sniff/converted_eink_image.png | |||
| Binary files differ | |||
diff --git a/images/crewctf24_sniff/device.jpg b/images/crewctf24_sniff/device.jpg new file mode 100644 index 0000000..b4341c9 --- /dev/null +++ b/images/crewctf24_sniff/device.jpg | |||
| Binary files differ | |||
diff --git a/images/crewctf24_sniff/digikey_datasheet.png b/images/crewctf24_sniff/digikey_datasheet.png new file mode 100644 index 0000000..8451edd --- /dev/null +++ b/images/crewctf24_sniff/digikey_datasheet.png | |||
| Binary files differ | |||
diff --git a/images/crewctf24_sniff/discord1.png b/images/crewctf24_sniff/discord1.png new file mode 100644 index 0000000..5210b70 --- /dev/null +++ b/images/crewctf24_sniff/discord1.png | |||
| Binary files differ | |||
diff --git a/images/crewctf24_sniff/discord2.png b/images/crewctf24_sniff/discord2.png new file mode 100644 index 0000000..3c9563f --- /dev/null +++ b/images/crewctf24_sniff/discord2.png | |||
| Binary files differ | |||
diff --git a/images/crewctf24_sniff/display1.jpg b/images/crewctf24_sniff/display1.jpg new file mode 100644 index 0000000..9e2b123 --- /dev/null +++ b/images/crewctf24_sniff/display1.jpg | |||
| Binary files differ | |||
diff --git a/images/crewctf24_sniff/display2.jpg b/images/crewctf24_sniff/display2.jpg new file mode 100644 index 0000000..9940a6c --- /dev/null +++ b/images/crewctf24_sniff/display2.jpg | |||
| Binary files differ | |||
diff --git a/images/crewctf24_sniff/everything.jpg b/images/crewctf24_sniff/everything.jpg new file mode 100644 index 0000000..b59aced --- /dev/null +++ b/images/crewctf24_sniff/everything.jpg | |||
| Binary files differ | |||
diff --git a/images/crewctf24_sniff/failed_flag.png b/images/crewctf24_sniff/failed_flag.png new file mode 100644 index 0000000..6748138 --- /dev/null +++ b/images/crewctf24_sniff/failed_flag.png | |||
| Binary files differ | |||
diff --git a/images/crewctf24_sniff/flag1.png b/images/crewctf24_sniff/flag1.png new file mode 100644 index 0000000..77eaa1f --- /dev/null +++ b/images/crewctf24_sniff/flag1.png | |||
| Binary files differ | |||
diff --git a/images/crewctf24_sniff/flag2.png b/images/crewctf24_sniff/flag2.png new file mode 100644 index 0000000..1f57257 --- /dev/null +++ b/images/crewctf24_sniff/flag2.png | |||
| Binary files differ | |||
diff --git a/images/crewctf24_sniff/logic1.jpg b/images/crewctf24_sniff/logic1.jpg new file mode 100644 index 0000000..1e35cab --- /dev/null +++ b/images/crewctf24_sniff/logic1.jpg | |||
| Binary files differ | |||
diff --git a/images/crewctf24_sniff/logic2.jpg b/images/crewctf24_sniff/logic2.jpg new file mode 100644 index 0000000..f6a5c75 --- /dev/null +++ b/images/crewctf24_sniff/logic2.jpg | |||
| Binary files differ | |||
diff --git a/images/crewctf24_sniff/logic2_i2c_1.png b/images/crewctf24_sniff/logic2_i2c_1.png new file mode 100644 index 0000000..fa4d16b --- /dev/null +++ b/images/crewctf24_sniff/logic2_i2c_1.png | |||
| Binary files differ | |||
diff --git a/images/crewctf24_sniff/logic2_i2c_2.png b/images/crewctf24_sniff/logic2_i2c_2.png new file mode 100644 index 0000000..96098de --- /dev/null +++ b/images/crewctf24_sniff/logic2_i2c_2.png | |||
| Binary files differ | |||
diff --git a/images/crewctf24_sniff/logic2_main.png b/images/crewctf24_sniff/logic2_main.png new file mode 100644 index 0000000..0d406ee --- /dev/null +++ b/images/crewctf24_sniff/logic2_main.png | |||
| Binary files differ | |||
diff --git a/images/crewctf24_sniff/logic2_spi.png b/images/crewctf24_sniff/logic2_spi.png new file mode 100644 index 0000000..f02c75f --- /dev/null +++ b/images/crewctf24_sniff/logic2_spi.png | |||
| Binary files differ | |||
diff --git a/images/crewctf24_sniff/logic2_spi_update_times.png b/images/crewctf24_sniff/logic2_spi_update_times.png new file mode 100644 index 0000000..11d9faf --- /dev/null +++ b/images/crewctf24_sniff/logic2_spi_update_times.png | |||
| Binary files differ | |||
diff --git a/images/crewctf24_sniff/pi1.jpg b/images/crewctf24_sniff/pi1.jpg new file mode 100644 index 0000000..794882b --- /dev/null +++ b/images/crewctf24_sniff/pi1.jpg | |||
| Binary files differ | |||
diff --git a/images/crewctf24_sniff/pi2.jpg b/images/crewctf24_sniff/pi2.jpg new file mode 100644 index 0000000..26e40f1 --- /dev/null +++ b/images/crewctf24_sniff/pi2.jpg | |||
| Binary files differ | |||
diff --git a/images/crewctf24_sniff/rpi_pinout.png b/images/crewctf24_sniff/rpi_pinout.png new file mode 100644 index 0000000..b8f4aaf --- /dev/null +++ b/images/crewctf24_sniff/rpi_pinout.png | |||
| Binary files differ | |||
diff --git a/images/deadface23-shattered_dreams-forum.png b/images/deadface23-shattered_dreams-forum.png new file mode 100644 index 0000000..ea9557a --- /dev/null +++ b/images/deadface23-shattered_dreams-forum.png | |||
| Binary files differ | |||
diff --git a/layouts/blog/rss.xml b/layouts/blog/rss.xml deleted file mode 100644 index 3d3ae80..0000000 --- a/layouts/blog/rss.xml +++ /dev/null | |||
| @@ -1,39 +0,0 @@ | |||
| 1 | {{- $pctx := . -}} | ||
| 2 | {{- if .IsHome -}}{{ $pctx = .Site }}{{- end -}} | ||
| 3 | {{- $pages := slice -}} | ||
| 4 | {{- if or $.IsHome $.IsSection -}} | ||
| 5 | {{- $pages = $pctx.RegularPages -}} | ||
| 6 | {{- else -}} | ||
| 7 | {{- $pages = $pctx.Pages -}} | ||
| 8 | {{- end -}} | ||
| 9 | {{- $limit := .Site.Config.Services.RSS.Limit -}} | ||
| 10 | {{- if ge $limit 1 -}} | ||
| 11 | {{- $pages = $pages | first $limit -}} | ||
| 12 | {{- end -}} | ||
| 13 | {{- printf "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" | safeHTML }} | ||
| 14 | <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> | ||
| 15 | <channel> | ||
| 16 | <title>{{ if eq .Title .Site.Title }}{{ .Site.Title }}{{ else }}{{ with .Title }}{{.}} on {{ end }}{{ .Site.Title }}{{ end }}</title> | ||
| 17 | <link>https://open.crates.im</link> | ||
| 18 | <description>Recent content {{ if ne .Title .Site.Title }}{{ with .Title }}in {{.}} {{ end }}{{ end }}on {{ .Site.Title }}</description> | ||
| 19 | <generator>Hugo -- gohugo.io</generator>{{ with .Site.LanguageCode }} | ||
| 20 | <language>{{.}}</language>{{end}}{{ with .Site.Author.email }} | ||
| 21 | <managingEditor>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</managingEditor>{{end}}{{ with .Site.Author.email }} | ||
| 22 | <webMaster>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</webMaster>{{end}}{{ with .Site.Copyright }} | ||
| 23 | <copyright>{{.}}</copyright>{{end}}{{ if not .Date.IsZero }} | ||
| 24 | <lastBuildDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</lastBuildDate>{{ end }} | ||
| 25 | {{ with .OutputFormats.Get "RSS" }} | ||
| 26 | {{ printf "<atom:link href=%q rel=\"self\" type=%q />" .Permalink .MediaType | safeHTML }} | ||
| 27 | {{ end }} | ||
| 28 | {{ range $pages }} | ||
| 29 | <item> | ||
| 30 | <title>{{ .Title }}</title> | ||
| 31 | <link>{{ .Permalink }}</link> | ||
| 32 | <pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</pubDate> | ||
| 33 | {{ with .Site.Author.email }}<author>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</author>{{end}} | ||
| 34 | <guid>{{ .Permalink }}</guid> | ||
| 35 | <description>{{- .Content | html -}}</description> | ||
| 36 | </item> | ||
| 37 | {{ end }} | ||
| 38 | </channel> | ||
| 39 | </rss> | ||
diff --git a/layouts/blog/section.html b/layouts/blog/section.html deleted file mode 100644 index 9466f77..0000000 --- a/layouts/blog/section.html +++ /dev/null | |||
| @@ -1,10 +0,0 @@ | |||
| 1 | <!doctype html> | ||
| 2 | <html lang="en"> | ||
| 3 | <meta charset="utf-8" /> | ||
| 4 | <title>{{.Title}}</title> | ||
| 5 | {{ $style := resources.Get "main.scss" | css.Sass | resources.Minify | resources.Fingerprint }} | ||
| 6 | <link rel="stylesheet" href="{{ $style.RelPermalink }}"> | ||
| 7 | |||
| 8 | <main> | ||
| 9 | {{.Content}} | ||
| 10 | </main> | ||
diff --git a/layouts/partials/foot.html b/layouts/partials/foot.html deleted file mode 100644 index 203510a..0000000 --- a/layouts/partials/foot.html +++ /dev/null | |||
| @@ -1,4 +0,0 @@ | |||
| 1 | <footer> | ||
| 2 | The content for the site is under <a href="/cc-by-4.0.txt">CC-BY-4.0</a>. | ||
| 3 | The code is under the <a href="/bsd_license.txt">2-Clause BSD License</a> unless specified otherwise. | ||
| 4 | </footer> | ||
diff --git a/layouts/partials/head.html b/layouts/partials/head.html deleted file mode 100644 index 3e6ccaa..0000000 --- a/layouts/partials/head.html +++ /dev/null | |||
| @@ -1,14 +0,0 @@ | |||
| 1 | <!doctype html> | ||
| 2 | <html lang="en"> | ||
| 3 | <head> | ||
| 4 | <meta charset="utf-8" /> | ||
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1" /> | ||
| 6 | {{ if $.Params.noindex }} | ||
| 7 | <meta name="robots" content="noindex"> | ||
| 8 | {{ end }} | ||
| 9 | <title>{{$.Title}}</title> | ||
| 10 | <link rel="alternate" type="application/rss+xml" title="RSS" href="https://vineetk.net/blog/index.xml"> | ||
| 11 | <link rel="icon" type="image/png" href="/AT_terminus.png"> | ||
| 12 | {{ $style := resources.Get "main.scss" | css.Sass | resources.Fingerprint }} | ||
| 13 | <link rel="stylesheet" href="{{ $style.RelPermalink }}"> | ||
| 14 | </head> | ||
diff --git a/posts/bctf23_electronical.md b/posts/bctf23_electronical.md new file mode 100644 index 0000000..3f82ecb --- /dev/null +++ b/posts/bctf23_electronical.md | |||
| @@ -0,0 +1,301 @@ | |||
| 1 | title: BCTF23 crypto/Electronical (medium) Writeup | ||
| 2 | date: 2023-10-26 12:00 | ||
| 3 | --- | ||
| 4 | |||
| 5 | > I do all my ciphering electronically. https://electronical.chall.pwnoh.io/ | ||
| 6 | |||
| 7 | When going to the linked site, you get told to encrypt any message or view the | ||
| 8 | site's source code. After submitting a message to encrypt, it returns some hex | ||
| 9 | string. | ||
| 10 | |||
| 11 | The source is: | ||
| 12 | ```python | ||
| 13 | from Crypto.Cipher import AES | ||
| 14 | from flask import Flask, request, abort, send_file | ||
| 15 | import math | ||
| 16 | import os | ||
| 17 | |||
| 18 | app = Flask(__name__) | ||
| 19 | |||
| 20 | key = os.urandom(32) | ||
| 21 | flag = os.environ.get('FLAG', 'bctf{fake_flag_fake_flag_fake_flag_fake_flag}') | ||
| 22 | |||
| 23 | cipher = AES.new(key, AES.MODE_ECB) | ||
| 24 | |||
| 25 | def encrypt(message: str) -> bytes: | ||
| 26 | length = math.ceil(len(message) / 16) * 16 | ||
| 27 | padded = message.encode().ljust(length, b'\0') | ||
| 28 | return cipher.encrypt(padded) | ||
| 29 | |||
| 30 | def decrypt(msg: str) -> bytes: | ||
| 31 | return cipher.decrypt(msg) | ||
| 32 | |||
| 33 | @app.get('/encrypt') | ||
| 34 | def handle_encrypt(): | ||
| 35 | param = request.args.get('message') | ||
| 36 | |||
| 37 | if not param: | ||
| 38 | return abort(400, "Bad") | ||
| 39 | if not isinstance(param, str): | ||
| 40 | return abort(400, "Bad") | ||
| 41 | |||
| 42 | print(encrypt(param + flag)) | ||
| 43 | |||
| 44 | return encrypt(param + flag).hex() | ||
| 45 | |||
| 46 | @app.get('/source') | ||
| 47 | def handle_source(): | ||
| 48 | return send_file(__file__, "text/plain") | ||
| 49 | |||
| 50 | @app.get('/') | ||
| 51 | def handle_home(): | ||
| 52 | return """ | ||
| 53 | <style> | ||
| 54 | form { | ||
| 55 | display: flex; | ||
| 56 | flex-direction: column; | ||
| 57 | max-width: 20em; | ||
| 58 | gap: .5em; | ||
| 59 | } | ||
| 60 | |||
| 61 | input { | ||
| 62 | padding: .4em; | ||
| 63 | } | ||
| 64 | </style> | ||
| 65 | <form action="/encrypt"> | ||
| 66 | <h2><i>ELECTRONICAL</i></h2> | ||
| 67 | <label for="message">Message to encrypt:</label> | ||
| 68 | <input id="message" name="message"></label> | ||
| 69 | <input type="submit" value="Submit"> | ||
| 70 | <a href="/source">Source code</a> | ||
| 71 | </form> | ||
| 72 | """ | ||
| 73 | |||
| 74 | if __name__ == "__main__": | ||
| 75 | app.run() | ||
| 76 | ``` | ||
| 77 | It seems that the flag is appended to the user's message and then encrypted with | ||
| 78 | AES-ECB. The total message is also padded to be a multiple of 16 bytes. | ||
| 79 | |||
| 80 | According to Wikipedia, ECB (electronic codebook) works by dividing a message | ||
| 81 | into blocks of a certain size (like 16 bytes). The problem however is that ECB | ||
| 82 | doesn't attempt to make any encrypted block unique like by adding a salt or | ||
| 83 | nonce, so any blocks of data that are identical would also be identical when | ||
| 84 | encrypted. Wikipedia also has an interesting example of encrypting an image of | ||
| 85 | Tux and a mountain (on French Wikipedia) with AES. | ||
| 86 | |||
| 87 |  | ||
| 88 | |||
| 89 |  | ||
| 90 | |||
| 91 | Through some more searching online, it seems a way to exploit this is with | ||
| 92 | something called a Chosen Plaintext Attack. Since the message before the flag is | ||
| 93 | controlled by us the user (attacker?) and the flag is appended to the end, the | ||
| 94 | provided message can be made in a way that only one byte of the flag needs to be | ||
| 95 | bruteforced at a time. | ||
| 96 | |||
| 97 | Let's say that this is our message: `thischallengesucksFLAG{5om3_!mp0r74nt_$3cr37}` | ||
| 98 | |||
| 99 | This string is 45 characters, so the server would pad this with 3 \0 characters | ||
| 100 | to make it evenly divisible by 16 characters. | ||
| 101 | |||
| 102 | ``` | ||
| 103 | b'thischallengesucksFLAG{5om3_!mp0r74nt_$3cr37}\x00\x00\x00' | ||
| 104 | ``` | ||
| 105 | |||
| 106 | We know what "thischallengesucks" is, but FLAG and anything else after is | ||
| 107 | appended by the server and is what we're trying to find. | ||
| 108 | |||
| 109 | "thischallengesucks" is 18 characters, but if we send a 15 character string, | ||
| 110 | then the first block to be encrypted would be "thischallengesu?", where ? is the | ||
| 111 | mystery character. | ||
| 112 | |||
| 113 | For readability purposes, I'm going to use repeated "0" characters needed | ||
| 114 | instead of "thischallengesucks". | ||
| 115 | |||
| 116 | When passing "000000000000000?" to the server, a certain hex string would be | ||
| 117 | returned (newlines every 32 characters not included in original): | ||
| 118 | |||
| 119 | ``` | ||
| 120 | b57189530dacbb9c5707c1cb0b044a34 | ||
| 121 | 5377049685bb9553a73e4408565505dd | ||
| 122 | 0c614f69c4749b10f8cbc9c735fd7314 | ||
| 123 | 5a9ae527825603a8eb0dba6a0347a4e5 | ||
| 124 | ``` | ||
| 125 | Replacing the ? with any other character would result in only the first row being | ||
| 126 | changed, like with "000000000000000A": | ||
| 127 | |||
| 128 | ``` | ||
| 129 | b2457a857e82a1d5ad919a4bdaf9133a | ||
| 130 | 7835c84bc75d836fad8ca5fbcec086ff | ||
| 131 | 937cf83a682fa26162a65f2295b2b119 | ||
| 132 | 6b398dd6f75e212b1633c5189bdb5689 | ||
| 133 | ``` | ||
| 134 | Since the other three blocks remained the same, the last character in the | ||
| 135 | message being sent simply needs to bruteforced with every printable character | ||
| 136 | until it results in the same block from ?. In this case, that character would be | ||
| 137 | F: | ||
| 138 | |||
| 139 | ``` | ||
| 140 | b57189530dacbb9c5707c1cb0b044a34 | ||
| 141 | 5377049685bb9553a73e4408565505dd | ||
| 142 | 0c614f69c4749b10f8cbc9c735fd7314 | ||
| 143 | 5a9ae527825603a8eb0dba6a0347a4e5 | ||
| 144 | ``` | ||
| 145 | ``` | ||
| 146 | (0000000000000, 14 characters long) | ||
| 147 | 5ec61f1209adfeff202edbba28339f83 | ||
| 148 | 4f7cc7a4c0c553380874383e93408678 | ||
| 149 | ca91d95b091956edb162da583b51051b | ||
| 150 | 33b91ab14b8807348fc98bf223b4b3a5 | ||
| 151 | |||
| 152 | (0000000000000FL, 16 characters long) | ||
| 153 | 5ec61f1209adfeff202edbba28339f83 | ||
| 154 | 4f7cc7a4c0c553380874383e93408678 | ||
| 155 | ca91d95b091956edb162da583b51051b | ||
| 156 | 33b91ab14b8807348fc98bf223b4b3a5 | ||
| 157 | ``` | ||
| 158 | Then the 0 left pad would be decreased by one character and the process repeats | ||
| 159 | until the whole block is done. However, a flag usually won't be just 16 | ||
| 160 | characters long. I had some difficulty trying to bruteforce the 17th character | ||
| 161 | and above because I was prepending and appending the zeros within a single block | ||
| 162 | (between 0 and 15 padded 0s), but that was among a few other issues I had that | ||
| 163 | were the result of the message I was sending being in the format of "pad + | ||
| 164 | known_flag + brute_single_char + pad" where this only worked for the first | ||
| 165 | block. This did not work later because those messages would have the pad bytes | ||
| 166 | in the middle of the message, which did not go well. | ||
| 167 | |||
| 168 | In the end, I realized that I can check the target block hexstring by sending | ||
| 169 | only the padded 0 bytes (or anything else of that length) without other | ||
| 170 | characters and then append my known bytes of the flag and a single other character | ||
| 171 | to fill that block to brute force that last character. | ||
| 172 | |||
| 173 | A visual representation is this: | ||
| 174 | |||
| 175 | ``` | ||
| 176 | Block size: 8 characters | ||
| 177 | |||
| 178 | 7 pad, 0 known | ||
| 179 | XXXXXXX? | ||
| 180 | XXXXXXXF | ||
| 181 | |||
| 182 | 6 pad, 1 known | ||
| 183 | XXXXXX?? | ||
| 184 | XXXXXXFL | ||
| 185 | |||
| 186 | 5 pad, 2 known | ||
| 187 | XXXXX??? | ||
| 188 | XXXXXFLA | ||
| 189 | |||
| 190 | ... | ||
| 191 | |||
| 192 | 0 pad, 7 known | ||
| 193 | FLAG{5o? | ||
| 194 | |||
| 195 | 8 known | ||
| 196 | FLAG{5om | ||
| 197 | ``` | ||
| 198 | This only decrypts the first block, so how I decrypted each additional block was | ||
| 199 | by prepending another block of pad characters (blocksize - 1) and repeating the | ||
| 200 | process. | ||
| 201 | |||
| 202 | ``` | ||
| 203 | 7 pad, 7 known | ||
| 204 | XXXXXXXFLAG{5om? | ||
| 205 | XXXXXXXFLAG{5om3 | ||
| 206 | |||
| 207 | 6 pad, 8 known | ||
| 208 | XXXXXXFLAG{5om3? | ||
| 209 | XXXXXXFLAG{5om3_ | ||
| 210 | |||
| 211 | ... | ||
| 212 | |||
| 213 | 5 pad, 26 known | ||
| 214 | XXXXXFLAG{5om3_!mp0r74nt_$3cr37? | ||
| 215 | XXXXXFLAG{5om3_!mp0r74nt_$3cr37} | ||
| 216 | |||
| 217 | ... | ||
| 218 | 0 pad, 31 known | ||
| 219 | FLAG{5om3_!mp0r74nt_$3cr37}\0\0? | ||
| 220 | FLAG{5om3_!mp0r74nt_$3cr37}\0\0\0 | ||
| 221 | ``` | ||
| 222 | After some automating help with python, I was able to finally get the flag. | ||
| 223 | |||
| 224 | ``` | ||
| 225 | Flag: bctf{1_c4n7_b3l13v3_u_f0und_my_c0d3b00k} | ||
| 226 | ``` | ||
| 227 | |||
| 228 | My python file to solve this was: | ||
| 229 | ```python | ||
| 230 | from requests import get | ||
| 231 | from requests.utils import quote | ||
| 232 | |||
| 233 | # list of characters that will be bruteforced, these are the printable chars | ||
| 234 | chars = [chr(i) for i in range(ord(' '), ord('~') + 1)] | ||
| 235 | # nul character is also checked because that's the pad character | ||
| 236 | chars += '\0' | ||
| 237 | |||
| 238 | def encrypt(msg): | ||
| 239 | #url = "https://electronical.chall.pwnoh.io/encrypt?message=" | ||
| 240 | url = "http://localhost:5000/encrypt?message=" | ||
| 241 | return get(url + quote(msg)).content; | ||
| 242 | |||
| 243 | def calc_padding_for_known(): | ||
| 244 | # divided by 2 because each hex byte is 2 characters long | ||
| 245 | cur = len(encrypt("0")) // 2 | ||
| 246 | |||
| 247 | # 16 chosen because that's the padding chosen in app.py on the server | ||
| 248 | for i in range(2, 16): | ||
| 249 | tmp = len(encrypt("0" * i)) // 2 | ||
| 250 | if tmp > cur: | ||
| 251 | return tmp, tmp - cur, i - 1 | ||
| 252 | # shouldn't come here | ||
| 253 | return 0,0,0 | ||
| 254 | |||
| 255 | totalblocks, bs, pad = calc_padding_for_known() | ||
| 256 | |||
| 257 | print(f"Block size of padding: {bs}, {pad}") | ||
| 258 | |||
| 259 | # first block are known to not be the flag (is all 0 being encrypted) | ||
| 260 | # second block is what's being bruteforced | ||
| 261 | # third block's last character is unknown and being compared with second block | ||
| 262 | #msg = "0" * (bs + bs - 1) + "a" * 1 + "0" * (bs - 1) | ||
| 263 | #cur = encrypt(msg) | ||
| 264 | #print(cur) | ||
| 265 | flag = "" | ||
| 266 | curflag = "" | ||
| 267 | |||
| 268 | tbs = bs * 2 | ||
| 269 | |||
| 270 | for j in range(totalblocks // bs): | ||
| 271 | for i in range(1, bs + 1): | ||
| 272 | known = "0" * (bs * (1 + j) - len(flag) - 1) | ||
| 273 | msg = known | ||
| 274 | target = encrypt(msg).decode("utf-8") | ||
| 275 | |||
| 276 | print(f"\nNew target message: {msg}") | ||
| 277 | print("New target message return:") | ||
| 278 | print('\n'.join([target[A:A + tbs] for A in range(0, len(target), tbs)])) | ||
| 279 | |||
| 280 | target = target[tbs * (0 + j):tbs * (1 + j)] | ||
| 281 | print(f"New target block: {target}") | ||
| 282 | |||
| 283 | for c in chars: | ||
| 284 | msg = known + flag + c | ||
| 285 | print(f"Current character: {c}") | ||
| 286 | print(f"Current message: {msg}") | ||
| 287 | print(f"Target block: {target}") | ||
| 288 | cur = encrypt(msg).decode("utf-8") | ||
| 289 | print('\n'.join([cur[A:A + tbs] for A in range(0, len(cur), tbs)])) | ||
| 290 | |||
| 291 | print(f"Current block: {cur[:tbs]}") | ||
| 292 | |||
| 293 | if (cur[tbs * (0 + j):tbs * (1 + j)] == target): | ||
| 294 | flag += c | ||
| 295 | print(flag) | ||
| 296 | break | ||
| 297 | |||
| 298 | print("\n") | ||
| 299 | curflag += flag | ||
| 300 | print(flag) | ||
| 301 | ``` | ||
diff --git a/posts/crewctf24_sniff.md b/posts/crewctf24_sniff.md new file mode 100644 index 0000000..32d1adb --- /dev/null +++ b/posts/crewctf24_sniff.md | |||
| @@ -0,0 +1,369 @@ | |||
| 1 | title: CrewCTF2024 misc/Sniff Writeup | ||
| 2 | date: 2024-08-04 12:00 | ||
| 3 | --- | ||
| 4 | ## Challenge | ||
| 5 | ### Description | ||
| 6 | > I came across this mysterious device. So I hooked up my logic analyzer | ||
| 7 | and recorded somebody using it. (`capture.sol`) | ||
| 8 | This challenge has two flags in the `flag{}` format | ||
| 9 | > * The first (easier) is the password that was typed on the keyboard. | ||
| 10 | > * The second (significantly harder) is what was display on the screen after the password was entered. | ||
| 11 | |||
| 12 | ### Images | ||
| 13 |  | ||
| 14 | |||
| 15 |  | ||
| 16 | |||
| 17 |  | ||
| 18 | |||
| 19 |  | ||
| 20 | |||
| 21 |  | ||
| 22 | |||
| 23 |  | ||
| 24 | |||
| 25 |  | ||
| 26 | |||
| 27 |  | ||
| 28 | |||
| 29 | ## Intro | ||
| 30 | Instead of sleeping, I made the mistake^Wwise decision of looking at my | ||
| 31 | Discord notification that said there was a hardware challenge in this CTF. It | ||
| 32 | just so happened that there it was using an ATmega-powered keyboard and an | ||
| 33 | e-paper screen, and it almost seemed like a coincidence since I was designing | ||
| 34 | my own keyboard and wanted to interface with an e-paper screen in the near | ||
| 35 | future. This seemed like a great learning opportunity so I started working on | ||
| 36 | the two-part challenge. | ||
| 37 | |||
| 38 | There were a few files inside the `dist.zip`, with the most | ||
| 39 | interesting one being capture.sal which was technically a zip but actually | ||
| 40 | the analyzer file for Salae. Sadly it seemed to need their proprietary | ||
| 41 | program to open. | ||
| 42 | |||
| 43 |  | ||
| 44 | |||
| 45 | The first thing I did was figuring out what each channel was connected to | ||
| 46 | and what it meant. It seemed that the keyboard and display were controlled by | ||
| 47 | the Raspberry Pi which then seemed to go to the logic analyzer. So I looked | ||
| 48 | at what each channel was connected to and based on its connected pin on the | ||
| 49 | Pi, I found its function via pinout.xyz. I ended up with this: | ||
| 50 | |||
| 51 | ``` | ||
| 52 | Channel 0: P03 I2C SDA | ||
| 53 | Channel 1: P05 I2C SCL | ||
| 54 | Channel 2: P11 GPIO 17 (busy) | ||
| 55 | Channel 3: P13 GPIO 27 (reset) | ||
| 56 | Channel 4: P15 GPIO 22 (data/command) | ||
| 57 | Channel 5: P21 MOSI | ||
| 58 | Channel 6: P23 SPI0 SCLK | ||
| 59 | Channel 7: P24 SPI0 CE0 | ||
| 60 | ``` | ||
| 61 | |||
| 62 |  | ||
| 63 | |||
| 64 | ## Part 1 | ||
| 65 | In Logic 2, I opened the I2C analyzer and outputted the dump in the | ||
| 66 | terminal tab into a file | ||
| 67 | |||
| 68 |  | ||
| 69 |  | ||
| 70 | It seemed there was a lot of NUL bytes being sent, probably indicating | ||
| 71 | that there wasn’t anything during that cycle, and a few seconds later there | ||
| 72 | were also some other different bytes with NUL and some `0x01` | ||
| 73 | bytes in between, and these seemed to be printable ASCII. | ||
| 74 | |||
| 75 | ``` | ||
| 76 | read to 0x5F ack data: 0x01 | ||
| 77 | read to 0x5F ack data: 0x01 | ||
| 78 | read to 0x5F ack data: 0x66 | ||
| 79 | read to 0x5F ack data: 0x6c | ||
| 80 | read to 0x5F ack data: 0x61 | ||
| 81 | read to 0x5F ack data: 0x67 | ||
| 82 | read to 0x5F ack data: 0x7b | ||
| 83 | read to 0x5F ack data: 0x37 | ||
| 84 | read to 0x5F ack data: 0x01 | ||
| 85 | read to 0x5F ack data: 0x31 | ||
| 86 | read to 0x5F ack data: 0x37 | ||
| 87 | read to 0x5F ack data: 0x66 | ||
| 88 | read to 0x5F ack data: 0x37 | ||
| 89 | read to 0x5F ack data: 0x35 | ||
| 90 | read to 0x5F ack data: 0x01 | ||
| 91 | read to 0x5F ack data: 0x33 | ||
| 92 | read to 0x5F ack data: 0x32 | ||
| 93 | read to 0x5F ack data: 0x7d | ||
| 94 | read to 0x5F ack data: 0x01 | ||
| 95 | read to 0x5F ack data: 0x0d | ||
| 96 | ``` | ||
| 97 | |||
| 98 | Filtering out the `0x00` and `0x01` data bytes and | ||
| 99 | converting to ASCII results in `flag{717f7532}`. | ||
| 100 | |||
| 101 | ## Part 2 | ||
| 102 |  | ||
| 103 | |||
| 104 | I first outputted the SPI dump from the analyzer into a file and kept only | ||
| 105 | the `MOSI` and `MISO` columns. | ||
| 106 | |||
| 107 | ``` | ||
| 108 | Time [s],Packet ID,MOSI,MISO | ||
| 109 | 4.108880200000000,0,0x12,0x00 | ||
| 110 | 5.109988000000000,0,0x01,0x00 | ||
| 111 | 5.110044320000000,0,0xF9,0xFF | ||
| 112 | 5.110062800000000,0,0x00,0xFF | ||
| 113 | 5.110081280000000,0,0x00,0xFF | ||
| 114 | 5.110125600000000,0,0x3A,0x00 | ||
| 115 | 5.110167440000000,0,0x1B,0xFF | ||
| 116 | 5.110210120000000,0,0x3B,0x00 | ||
| 117 | 5.110251760000000,0,0x0B,0xFF | ||
| 118 | ``` | ||
| 119 | |||
| 120 | To actually understand what’s going on, I couldn’t find any proper | ||
| 121 | documentation initially. There wasn’t even a proper datasheet on DigiKey; the | ||
| 122 | “datasheet” was just a summary of the product. | ||
| 123 | |||
| 124 |  | ||
| 125 | |||
| 126 | Then I found the [Python library | ||
| 127 | source from Pimoroni](https://github.com/pimoroni/inky) of their epaper screens, which is probably what was | ||
| 128 | used to make this challenge. | ||
| 129 | |||
| 130 | ```python | ||
| 131 | def setup(self): | ||
| 132 | """Set up Inky GPIO and reset display.""" | ||
| 133 | if not self._gpio_setup: | ||
| 134 | if self._gpio is None: | ||
| 135 | try: | ||
| 136 | import RPi.GPIO as GPIO | ||
| 137 | self._gpio = GPIO | ||
| 138 | except ImportError: | ||
| 139 | raise ImportError('This library requires the RPi.GPIO module\nInstall with: sudo apt install python-rpi.gpio') | ||
| 140 | self._gpio.setmode(self._gpio.BCM) | ||
| 141 | self._gpio.setwarnings(False) | ||
| 142 | self._gpio.setup(self.dc_pin, self._gpio.OUT, initial=self._gpio.LOW, pull_up_down=self._gpio.PUD_OFF) | ||
| 143 | self._gpio.setup(self.reset_pin, self._gpio.OUT, initial=self._gpio.HIGH, pull_up_down=self._gpio.PUD_OFF) | ||
| 144 | self._gpio.setup(self.busy_pin, self._gpio.IN, pull_up_down=self._gpio.PUD_OFF) | ||
| 145 | |||
| 146 | if self._spi_bus is None: | ||
| 147 | import spidev | ||
| 148 | self._spi_bus = spidev.SpiDev() | ||
| 149 | |||
| 150 | self._spi_bus.open(0, self.cs_pin) | ||
| 151 | self._spi_bus.max_speed_hz = 488000 | ||
| 152 | |||
| 153 | self._gpio_setup = True | ||
| 154 | |||
| 155 | self._gpio.output(self.reset_pin, self._gpio.LOW) | ||
| 156 | time.sleep(0.5) | ||
| 157 | self._gpio.output(self.reset_pin, self._gpio.HIGH) | ||
| 158 | time.sleep(0.5) | ||
| 159 | |||
| 160 | self._send_command(0x12) # Soft Reset | ||
| 161 | time.sleep(1.0) | ||
| 162 | self._busy_wait() | ||
| 163 | |||
| 164 | def _update(self, buf_a, buf_b, busy_wait=True): | ||
| 165 | """Update display. | ||
| 166 | |||
| 167 | Dispatches display update to correct driver. | ||
| 168 | |||
| 169 | :param buf_a: Black/White pixels | ||
| 170 | :param buf_b: Yellow/Red pixels | ||
| 171 | |||
| 172 | """ | ||
| 173 | self.setup() | ||
| 174 | |||
| 175 | self._send_command(ssd1608.DRIVER_CONTROL, [self.rows - 1, (self.rows - 1) >> 8, 0x00]) | ||
| 176 | # Set dummy line period | ||
| 177 | self._send_command(ssd1608.WRITE_DUMMY, [0x1B]) | ||
| 178 | # Set Line Width | ||
| 179 | self._send_command(ssd1608.WRITE_GATELINE, [0x0B]) | ||
| 180 | # Data entry squence (scan direction leftward and downward) | ||
| 181 | self._send_command(ssd1608.DATA_MODE, [0x03]) | ||
| 182 | # Set ram X start and end position | ||
| 183 | xposBuf = [0x00, self.cols // 8 - 1] | ||
| 184 | self._send_command(ssd1608.SET_RAMXPOS, xposBuf) | ||
| 185 | # Set ram Y start and end position | ||
| 186 | yposBuf = [0x00, 0x00, (self.rows - 1) & 0xFF, (self.rows - 1) >> 8] | ||
| 187 | self._send_command(ssd1608.SET_RAMYPOS, yposBuf) | ||
| 188 | # VCOM Voltage | ||
| 189 | self._send_command(ssd1608.WRITE_VCOM, [0x70]) | ||
| 190 | # Write LUT DATA | ||
| 191 | self._send_command(ssd1608.WRITE_LUT, self._luts[self.lut]) | ||
| 192 | |||
| 193 | if self.border_colour == self.BLACK: | ||
| 194 | self._send_command(ssd1608.WRITE_BORDER, 0b00000000) | ||
| 195 | # GS Transition + Waveform 00 + GSA 0 + GSB 0 | ||
| 196 | elif self.border_colour == self.RED and self.colour == 'red': | ||
| 197 | self._send_command(ssd1608.WRITE_BORDER, 0b00000110) | ||
| 198 | # GS Transition + Waveform 01 + GSA 1 + GSB 0 | ||
| 199 | elif self.border_colour == self.YELLOW and self.colour == 'yellow': | ||
| 200 | self._send_command(ssd1608.WRITE_BORDER, 0b00001111) | ||
| 201 | # GS Transition + Waveform 11 + GSA 1 + GSB 1 | ||
| 202 | elif self.border_colour == self.WHITE: | ||
| 203 | self._send_command(ssd1608.WRITE_BORDER, 0b00000001) | ||
| 204 | # GS Transition + Waveform 00 + GSA 0 + GSB 1 | ||
| 205 | |||
| 206 | # Set RAM address to 0, 0 | ||
| 207 | self._send_command(ssd1608.SET_RAMXCOUNT, [0x00]) | ||
| 208 | self._send_command(ssd1608.SET_RAMYCOUNT, [0x00, 0x00]) | ||
| 209 | |||
| 210 | for data in ((ssd1608.WRITE_RAM, buf_a), (ssd1608.WRITE_ALTRAM, buf_b)): | ||
| 211 | cmd, buf = data | ||
| 212 | self._send_command(cmd, buf) | ||
| 213 | |||
| 214 | self._busy_wait() | ||
| 215 | self._send_command(ssd1608.MASTER_ACTIVATE) | ||
| 216 | ``` | ||
| 217 | |||
| 218 | It was also communicating over SPI which seemed to indicate that this was | ||
| 219 | the proper library. Then I looked at the `setup()` and | ||
| 220 | `_update()` functions in | ||
| 221 | `library/inky/inky_ssd1608.py`, and the SPI commands that were | ||
| 222 | sent in the analyzed dump log matched exactly, including each byte of the LUT | ||
| 223 | table. | ||
| 224 | |||
| 225 | All the SPI commands used in the library are used with named constants | ||
| 226 | that are defined `library/inky/ssd1608.py`: | ||
| 227 | |||
| 228 | ```python | ||
| 229 | """Constants for SSD1608 driver IC.""" | ||
| 230 | DRIVER_CONTROL = 0x01 | ||
| 231 | GATE_VOLTAGE = 0x03 | ||
| 232 | SOURCE_VOLTAGE = 0x04 | ||
| 233 | DISPLAY_CONTROL = 0x07 | ||
| 234 | NON_OVERLAP = 0x0B | ||
| 235 | BOOSTER_SOFT_START = 0x0C | ||
| 236 | GATE_SCAN_START = 0x0F | ||
| 237 | DEEP_SLEEP = 0x10 | ||
| 238 | DATA_MODE = 0x11 | ||
| 239 | SW_RESET = 0x12 | ||
| 240 | TEMP_WRITE = 0x1A | ||
| 241 | TEMP_READ = 0x1B | ||
| 242 | TEMP_CONTROL = 0x1C | ||
| 243 | TEMP_LOAD = 0x1D | ||
| 244 | MASTER_ACTIVATE = 0x20 | ||
| 245 | DISP_CTRL1 = 0x21 | ||
| 246 | DISP_CTRL2 = 0x22 | ||
| 247 | WRITE_RAM = 0x24 | ||
| 248 | WRITE_ALTRAM = 0x26 | ||
| 249 | READ_RAM = 0x25 | ||
| 250 | VCOM_SENSE = 0x28 | ||
| 251 | VCOM_DURATION = 0x29 | ||
| 252 | WRITE_VCOM = 0x2C | ||
| 253 | READ_OTP = 0x2D | ||
| 254 | WRITE_LUT = 0x32 | ||
| 255 | WRITE_DUMMY = 0x3A | ||
| 256 | WRITE_GATELINE = 0x3B | ||
| 257 | WRITE_BORDER = 0x3C | ||
| 258 | SET_RAMXPOS = 0x44 | ||
| 259 | SET_RAMYPOS = 0x45 | ||
| 260 | SET_RAMXCOUNT = 0x4E | ||
| 261 | SET_RAMYCOUNT = 0x4F | ||
| 262 | NOP = 0xFF | ||
| 263 | ``` | ||
| 264 | |||
| 265 | I then noticed that there was a long string of bytes being sent after a | ||
| 266 | `0x24` which in the library indicated that it was the memory | ||
| 267 | buffer for the black/white channel ending with a `0x00` | ||
| 268 | `MISO`, with the yellow/red channel afterward with a | ||
| 269 | `0x26` `MOSI` and also ended with `0x00` | ||
| 270 | `MISO` | ||
| 271 | |||
| 272 | ``` | ||
| 273 | ... | ||
| 274 | 0x19,0xFF | ||
| 275 | 0x01,0xFF | ||
| 276 | 0x00,0xFF | ||
| 277 | 0x3C,0x00 | ||
| 278 | 0x01,0xFF | ||
| 279 | 0x4E,0x00 | ||
| 280 | 0x00,0xFF | ||
| 281 | 0x4F,0x00 | ||
| 282 | 0x00,0xFF | ||
| 283 | 0x00,0xFF | ||
| 284 | 0x24,0x00 | ||
| 285 | 0xFF,0xFF | ||
| 286 | 0xFF,0xFF | ||
| 287 | 0xFF,0xFF | ||
| 288 | 0xFF,0xFF | ||
| 289 | 0xFF,0xFF | ||
| 290 | 0xFF,0xFF | ||
| 291 | 0xFF,0xFF | ||
| 292 | 0xFF,0xFF | ||
| 293 | 0xFF,0xFF | ||
| 294 | 0xFF,0xFF | ||
| 295 | ... | ||
| 296 | ``` | ||
| 297 | |||
| 298 | There also seemed to be two different updates at around 5 seconds and 70 | ||
| 299 | seconds. | ||
| 300 | |||
| 301 |  | ||
| 302 | |||
| 303 | However, the number of bytes written was 4250, which wasn’t the 3812.5 or | ||
| 304 | 2756 bytes I was expecting. This wasn’t divisible by 250 nor 122 and so I was | ||
| 305 | stuck for a long time. Looking through the library source for more than an | ||
| 306 | hour with my tired self didn’t help much either. As a last ditch attempt, I | ||
| 307 | tried converting the raw bytes into an image via Pillow, I used the | ||
| 308 | `L` mode (`8bpp`) and just got an uninteresting garbled | ||
| 309 | image. | ||
| 310 | |||
| 311 |  | ||
| 312 | |||
| 313 | ## Part 2 Part 2: Electric Boogaloo | ||
| 314 |  | ||
| 315 |  | ||
| 316 | |||
| 317 | After waking up and working on the CTF after it ended, my partner asked on | ||
| 318 | the Discord and found some interesting very helpful information. It turned | ||
| 319 | out the image was a packed 1bpp image. This meant that each byte in the | ||
| 320 | memory framebuffer contained 8 pixels (8 bits / 1 bits per pixel = 8 | ||
| 321 | pixels). | ||
| 322 | |||
| 323 | ```python | ||
| 324 | # under show() | ||
| 325 | buf_a = numpy.packbits(numpy.where(region == BLACK, 0, 1)).tolist() | ||
| 326 | buf_b = numpy.packbits(numpy.where(region == RED, 1, 0)).tolist() | ||
| 327 | ``` | ||
| 328 | |||
| 329 | In the Python source, this was shown by `buf_a` and | ||
| 330 | `buf_b` being packed bits of 1bpp via NumPy. I don’t know much | ||
| 331 | about NumPy, so this was a skill issue as I initially assumed it was a | ||
| 332 | complicated way of saving all the black and red pixels into lists. This is a | ||
| 333 | good reminder that the documentation should be checked for all unfamiliar | ||
| 334 | functions instead of naively assuming what they seem to do. | ||
| 335 | |||
| 336 | Also in addition to the screen being rotated by 90 degrees, the vertical | ||
| 337 | resolution is actually 136 pixels and not 120 according to the driver. | ||
| 338 | |||
| 339 | Knowing all this solved all my problems as 4250 * 8 was indeed divisible | ||
| 340 | by 250 and the actual vertical resolution 136. | ||
| 341 | |||
| 342 | All I had to do was change the Pillow mode when converting the bytes to an | ||
| 343 | image from `L` (8bpp) to `1` (1bpp) and the (rotated) | ||
| 344 | resolution from `(250, 16)` to `(136, 250)` and got an | ||
| 345 | actual image. | ||
| 346 | |||
| 347 |  | ||
| 348 | |||
| 349 | I used the first updated bytes which was the screen shown in the | ||
| 350 | challenge’s screenshots. Using the second update’s bytes gave half of the | ||
| 351 | flag in the black/white channel and the other half in the yellow/red | ||
| 352 | channel. | ||
| 353 | |||
| 354 |  | ||
| 355 |  | ||
| 356 | |||
| 357 | Each character index in both channels seemed to alternate, so the actual | ||
| 358 | flag was `flag{ec9cf2b7}`. After I finished writing this writeup | ||
| 359 | and seeing the two images side-by-side, they probably could’ve been overlayed | ||
| 360 | after one’s colours are inverted, and is probably what was meant by | ||
| 361 | “stitching” the channels together. | ||
| 362 | |||
| 363 | ## Conclusion | ||
| 364 | This was my most favourite CTF challenge by far and I learned a lot, | ||
| 365 | especially about stuff I wanted to learn like how SPI e-paper screens work | ||
| 366 | and not be lost with I2C. I am personally now curious whether the SPI screens | ||
| 367 | can be interfaced directly with the MCU instead of going through an | ||
| 368 | intermediate daughterboard/HAT and how different the protocol for parallel | ||
| 369 | screens are since they’re much faster and use more pins. | ||
diff --git a/posts/csaw23_rebug1.md b/posts/csaw23_rebug1.md new file mode 100644 index 0000000..7e21285 --- /dev/null +++ b/posts/csaw23_rebug1.md | |||
| @@ -0,0 +1,97 @@ | |||
| 1 | title: CSAW23 rev/Rebug1 Writeup | ||
| 2 | date: 2023-09-28 12:00 | ||
| 3 | --- | ||
| 4 | > Can't seem to print out the flag :( Can you figure how to get the flag | ||
| 5 | with this binary? | ||
| 6 | |||
| 7 | An innocent looking binary is given that asks for a string: | ||
| 8 | |||
| 9 | ``` | ||
| 10 | ./test.out | ||
| 11 | Enter the String: rptuainadui | ||
| 12 | that isn't correct, im sorry! | ||
| 13 | ``` | ||
| 14 | |||
| 15 | This is part of the rev category (which I think is for reverse | ||
| 16 | engineering). You could bruteforce this yes, but I found it easier | ||
| 17 | to put this into a decompiler like the ones on [DogBolt (Decompiler | ||
| 18 | Explorer)](https://dogbolt.org/) to see what it's doing. | ||
| 19 | |||
| 20 | Decompiled main function (via angr): | ||
| 21 | |||
| 22 | ``` | ||
| 23 | int main() | ||
| 24 | { | ||
| 25 | char v0; // [bp-0x448] | ||
| 26 | unsigned int v1; // [bp-0x41c] | ||
| 27 | char v2; // [bp-0x418] | ||
| 28 | char v3; // [bp-0x408] | ||
| 29 | unsigned long long v4; // [bp-0x18] | ||
| 30 | unsigned int v5; // [bp-0x10] | ||
| 31 | unsigned int v6; // [bp-0xc] | ||
| 32 | unsigned long long v8; // rax | ||
| 33 | |||
| 34 | printf("Enter the String: "); | ||
| 35 | __isoc99_scanf("%s", (unsigned int)&v3); | ||
| 36 | for (v6 = 0; (&v3)[v6]; v6 += 1); | ||
| 37 | if (v6 == 12) | ||
| 38 | { | ||
| 39 | puts("that's correct!"); | ||
| 40 | v4 = EVP_MD_CTX_new(); | ||
| 41 | (unsigned int)v8 = EVP_md5(); | ||
| 42 | EVP_DigestInit_ex(v4, v8, 0x0, v8); | ||
| 43 | EVP_DigestUpdate(v4, "12", 0x2, "12"); | ||
| 44 | v1 = 16; | ||
| 45 | EVP_DigestFinal_ex(v4, &v2, &v1, &v2); | ||
| 46 | EVP_MD_CTX_free(v4); | ||
| 47 | for (v5 = 0; v5 <= 15; v5 += 1) | ||
| 48 | { | ||
| 49 | sprintf(&(&v0)[2 * v5], "%02x", (&v2)[v5]); | ||
| 50 | } | ||
| 51 | printf("csawctf{%s}\n", (unsigned int)&v0); | ||
| 52 | return 0; | ||
| 53 | } | ||
| 54 | printf("that isn't correct, im sorry!"); | ||
| 55 | return 0; | ||
| 56 | } | ||
| 57 | ``` | ||
| 58 | |||
| 59 | This along with the rest of the decompiled binary can't be simply compiled again | ||
| 60 | as-is because there are a few issues, like the OpenSSL functions being called | ||
| 61 | having an extra argument added to the end. | ||
| 62 | |||
| 63 | When looking at the functions being called, it seems that the flag is just an | ||
| 64 | md5 of the number 12. The program also seems to give the flag itself if you give | ||
| 65 | it the character with the ASCII value of 12 (form feed). | ||
| 66 | |||
| 67 | The line that that has the data being checksummed is this: | ||
| 68 | |||
| 69 | ``` | ||
| 70 | EVP_DigestUpdate(v4, "12", 0x2, "12"); | ||
| 71 | ``` | ||
| 72 | |||
| 73 | I did try piping the form feed character via printf to the binary, but it did | ||
| 74 | not like that, so it seems that the only way to get the flag is through another | ||
| 75 | way. | ||
| 76 | |||
| 77 | While you could just create a very simplified version of the decompiled source | ||
| 78 | with OpenSSL's crypto library (which is what I did originally), it's much easier | ||
| 79 | to just pass the number 12 to a pre-installed md5 command (md5 on OpenBSD, | ||
| 80 | md5sum on Linux). | ||
| 81 | |||
| 82 | ``` | ||
| 83 | $ echo -n 12 | md5 | ||
| 84 | c20ad4d76fe97759aa27a0c99bff6710 | ||
| 85 | ``` | ||
| 86 | |||
| 87 | This CTF's flags were in the format of csawctf{somethinghere}, as also seen in | ||
| 88 | the decompiled source, so the actual flag was this: | ||
| 89 | |||
| 90 | ``` | ||
| 91 | csawctf{c20ad4d76fe97759aa27a0c99bff6710} | ||
| 92 | ``` | ||
| 93 | |||
| 94 | This was my first time doing any decompilation of a program, and I think this | ||
| 95 | was a good start to learn reverse engineering. | ||
| 96 | |||
| 97 | ``` \ No newline at end of file | ||
diff --git a/posts/deadface23_hostbusters3.md b/posts/deadface23_hostbusters3.md new file mode 100644 index 0000000..238ea65 --- /dev/null +++ b/posts/deadface23_hostbusters3.md | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | title: "DEADFACE CTF 2023 Host Busters 3 Writeup" | ||
| 2 | date: 2023-10-26 12:00 | ||
| 3 | --- | ||
| 4 | > Continue characterizing the machine. Is there any way you can | ||
| 5 | escalate to a user that has permissions the vim user does not have? Find | ||
| 6 | the flag associated with this user. | ||
| 7 | Submit the flag as `flag{flag_here}`. | ||
| 8 | |||
| 9 | ``` | ||
| 10 | vim@ghost404.deadface.io letmevim | ||
| 11 | ``` | ||
| 12 | |||
| 13 | You first login to vim, which has vim open. Then you escape from it like you | ||
| 14 | did in the OverTheWire Bandit challenges with `:set shell=bash` and `:shell`. Now you have a proper shell over SSH. | ||
| 15 | |||
| 16 | The first thing I looked at after mistaking Host Busters 1's key in the home | ||
| 17 | directory as 3 was look at what other user home directories there were by | ||
| 18 | running `ls /home`. I saw there were a few users, notably `gh0st404` and | ||
| 19 | `spookyboi`. | ||
| 20 | |||
| 21 | `gh0st404`'s user home directory had his OpenSSH private key as | ||
| 22 | world-readable and in plain sight not in his `.ssh` hidden | ||
| 23 | directory. It being world-readable would have had OpenSSH scream at you, but | ||
| 24 | them being stupid was good for us. | ||
| 25 | |||
| 26 | So, once you use that SSH private key to login as `gh0st404`, | ||
| 27 | you can check the contents of hostbusters3.txt and you got the flag. | ||
| 28 | |||
| 29 | ``` | ||
| 30 | cat hostbusters3.txt | ||
| 31 | ``` | ||
| 32 | |||
| 33 | > "This is why you should have come to the Monday meetings for OverTheWire." | ||
| 34 | ~Joey, FPUSEC President | ||
| 35 | |||
| 36 | [Here's](https://asciinema.org/a/ZhQQwEVwgaqtGCuaqRf6NWu8N) an | ||
| 37 | asciinema of the entire thing in action. | ||
diff --git a/posts/deadface23_shattered-dreams.md b/posts/deadface23_shattered-dreams.md new file mode 100644 index 0000000..899433c --- /dev/null +++ b/posts/deadface23_shattered-dreams.md | |||
| @@ -0,0 +1,166 @@ | |||
| 1 | title: DEADFACE CTF 2023 Shattered Dreams Writeup | ||
| 2 | date: 2023-10-26 12:00 | ||
| 3 | --- | ||
| 4 | > DEADFACE is on the brink of selling a patient's credit card details from the | ||
| 5 | Aurora database to a dark web buyer. Investigate Ghost Town for potential leads | ||
| 6 | on the victim's identity. | ||
| 7 | |||
| 8 | A huge hint was dropped immediately, so I went to Ghost Town to find a thread | ||
| 9 | titled "We got a potential buyer". | ||
| 10 | |||
| 11 | The flag's format is `flag{Firstname Lastname}`. | ||
| 12 | |||
| 13 | lilith, the original poster of the thread, said the victim's SHA1 hash we need | ||
| 14 | to look for is "911d1fc5930fa5025dbc2d3953c94de9e4773584" and showed how she | ||
| 15 | calculated that, including the (lack of) delimeter. | ||
| 16 | |||
| 17 |  | ||
| 18 | |||
| 19 | So, we can easily bruteforce getting this SHA1 hash by repeating what lilith | ||
| 20 | did. | ||
| 21 | |||
| 22 | The first three fields (card number, expiration, CCV) are values from the | ||
| 23 | billing table and the rest of the fields is all the fields in the patient | ||
| 24 | table. | ||
| 25 | |||
| 26 | ```sql | ||
| 27 | CREATE TABLE `billing` ( | ||
| 28 | `billing_id` int(11) NOT NULL AUTO_INCREMENT, | ||
| 29 | `patient_id` int(11) NOT NULL, | ||
| 30 | `credit_type_id` int(11) NOT NULL, | ||
| 31 | `card_num` varchar(24) NOT NULL, | ||
| 32 | `exp` varchar(8) NOT NULL, | ||
| 33 | `ccv` varchar(4) NOT NULL, | ||
| 34 | PRIMARY KEY (`billing_id`), | ||
| 35 | UNIQUE KEY `card_num` (`card_num`), | ||
| 36 | KEY `fk_billing_patient_id` (`patient_id`), | ||
| 37 | KEY `fk_billing_credit_type_id` (`credit_type_id`), | ||
| 38 | CONSTRAINT `fk_billing_credit_type_id` FOREIGN KEY (`credit_type_id`) REFERENCES `credit_types` (`credit_type_id`) ON DELETE CASCADE, | ||
| 39 | CONSTRAINT `fk_billing_patient_id` FOREIGN KEY (`patient_id`) REFERENCES `patients` (`patient_id`) ON DELETE CASCADE | ||
| 40 | ) ENGINE=InnoDB AUTO_INCREMENT=14443 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; | ||
| 41 | ... | ||
| 42 | CREATE TABLE `patients` ( | ||
| 43 | `patient_id` int(11) NOT NULL AUTO_INCREMENT, | ||
| 44 | `first_name` varchar(32) NOT NULL, | ||
| 45 | `last_name` varchar(64) NOT NULL, | ||
| 46 | `middle` varchar(8) DEFAULT NULL, | ||
| 47 | `sex` varchar(8) NOT NULL, | ||
| 48 | `email` varchar(128) NOT NULL, | ||
| 49 | `street` varchar(64) NOT NULL, | ||
| 50 | `city` varchar(64) NOT NULL, | ||
| 51 | `state` varchar(8) NOT NULL, | ||
| 52 | `zip` varchar(12) NOT NULL, | ||
| 53 | `dob` date NOT NULL, | ||
| 54 | PRIMARY KEY (`patient_id`), | ||
| 55 | UNIQUE KEY `email` (`email`) | ||
| 56 | ) ENGINE=InnoDB AUTO_INCREMENT=18542 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; | ||
| 57 | ``` | ||
| 58 | |||
| 59 | Since there are no delimeters, they can just be concatenated with each other | ||
| 60 | and then piped to sha1. The difficult part I had was properly concatenating | ||
| 61 | those values because I was not able to read the MySQL dump with sqlite3 nor | ||
| 62 | mariadb. | ||
| 63 | |||
| 64 | I noticed that each of the rows that were inserted into the tables were | ||
| 65 | delimited by a comma, similar to CSV. | ||
| 66 | |||
| 67 | ```sql | ||
| 68 | INSERT INTO `patients` VALUES (8151,'Lorrayne','Covey','E','Female','lcovey0@wunderground.com','40411 Old Shore Street','Houston','TX','77201','1985-02-08'),(8152,'Eddy','Omand','S','Female','eomand1@mysql.com','454 Pine View Alley','Columbus','OH','43226','1959-09-29'),(8153,'Renard','Berre','O','Male','rberre2@friendfeed.com','3496 Merrick Center','Pittsburgh','PA','15235','1978-12-05'),(8154,'Galven','Nardrup','M','Male','gnardrup3@mac.com','0 American Road','Denver','CO','80241','1984-04-09'), ... | ||
| 69 | ``` | ||
| 70 | |||
| 71 | So I was able to easily convert it into a CSV with the following command: | ||
| 72 | |||
| 73 | ```bash | ||
| 74 | grep 'INSERT INTO `patients`' aurora.sql \ | ||
| 75 | | sed 's/^INSERT[^(]*//' \ | ||
| 76 | | awk '{gsub(/,\(/, "\n"); gsub(/\)*/, ""); print}' | ||
| 77 | ``` | ||
| 78 | |||
| 79 | Part of the output is now: | ||
| 80 | |||
| 81 | ``` | ||
| 82 | ...18532,'Becka','Hurlin','T','Female','bhurlin80d@yolasite.com','58 Amoth Way','Ventura','CA','93005','1953-11-14' | ||
| 83 | 18533,'Aluin','Horwell','O','Male','ahorwell80e@cbc.ca','3 Oriole Terrace','Miami','FL','33190','1984-06-24' | ||
| 84 | 18534,'Glennis','Walder','R','Female','gwalder80f@cnet.com','966 Packers Hill','Topeka','KS','66617','1950-01-21' | ||
| 85 | ... | ||
| 86 | ``` | ||
| 87 | |||
| 88 | One problem I had when I used tr to replace ( with \n was that one of the names | ||
| 89 | had () in their name for some reason, which messed up the concatenating of the | ||
| 90 | two files to get the hash. I originally just manually edited it, but the above | ||
| 91 | with awk is cleaner. The same goes with the 'INSERT INTO ...' part messing things up for the same reason. I didn't save my ~/.ksh_history file with the | ||
| 92 | commands I ran, so this is a non-ugly version I remade with more awk. | ||
| 93 | |||
| 94 | To properly concatenate the data fields, the comma and single quotes should | ||
| 95 | also be removed, which tr can be used for unlike before. | ||
| 96 | |||
| 97 | ```bash | ||
| 98 | grep 'INSERT INTO `patients`' aurora.sql \ | ||
| 99 | | sed 's/^INSERT[^(]*//' \ | ||
| 100 | | awk '{gsub(/,\(/, "\n"); gsub(/\)*/, ""); print}' \ | ||
| 101 | | tr -d "'," >patients_.txt | ||
| 102 | ``` | ||
| 103 | |||
| 104 | Part of the output prior to being written to a file is now: | ||
| 105 | |||
| 106 | ``` | ||
| 107 | 18527TannerMasselinAMaletmasselin808@google.es10080 Reindahl CourtBoca RatonFL334871957-08-15 | ||
| 108 | 18528MerrelYeudeDMalemyeude809@ca.gov7934 Katie PassSaint PaulMN551881951-04-07 | ||
| 109 | 18529JeffVan BaarenMMalejvanbaaren80a@sphinn.com58097 Autumn Leaf DriveNew OrleansLA701421984-01-13 | ||
| 110 | ``` | ||
| 111 | |||
| 112 | It is written to a file so that it can be easy to concatenate both the billing | ||
| 113 | and patient data by using the paste command. | ||
| 114 | |||
| 115 | The next part is doing the same with the billing data. Unlike with the patient | ||
| 116 | data, only three fields from the billing table is used instead of all, so cut | ||
| 117 | or awk can be used with the delimeter set to a comma. | ||
| 118 | |||
| 119 | Before that, we need to know what index (base 1) the three fields are at. The | ||
| 120 | credit card number, expiry date, and ccv are fields 4, 5, and 6. | ||
| 121 | |||
| 122 | ```bash | ||
| 123 | grep 'INSERT INTO `billing`' aurora.sql \ | ||
| 124 | | sed 's/^INSERT[^(]*//' \ | ||
| 125 | | awk '{gsub(/,\(/, "\n"); gsub(/\)*/, ""); print}' \ | ||
| 126 | | cut -d, -f4,5,6 \ | ||
| 127 | | tr -d "'," >billing_.txt | ||
| 128 | ``` | ||
| 129 | |||
| 130 | Some of the output looks like | ||
| 131 | |||
| 132 | ``` | ||
| 133 | 51087507745678202025-01403 | ||
| 134 | 50483770976260922023-07242 | ||
| 135 | 50483739134688352023-12501 | ||
| 136 | ``` | ||
| 137 | |||
| 138 | Both tables with the fields have been parsed and saved to two different files, but simply using cat on both the files would simply print the contents of the second file after the first file has finished printing, but we need each line of both the files to be joined together! That's where the paste command comes in. It combines each line of its input files, which is exactly what is required. | ||
| 139 | |||
| 140 | These merged lines are then fed into sha1, and finally grep can be used to look for the hash we need and print the victim's name if it shows up. | ||
| 141 | |||
| 142 | ```bash | ||
| 143 | target_hash="911d1fc5930fa5025dbc2d3953c94de9e4773584" | ||
| 144 | |||
| 145 | paste billing_.txt patients_.txt | tr -d '\t' \ | ||
| 146 | | while read line; do | ||
| 147 | echo -n "$line" | sha1 \ | ||
| 148 | | grep "$target_hash" && echo "$line" && break | ||
| 149 | done | ||
| 150 | ``` | ||
| 151 | |||
| 152 | The outputted line of the victim who had the same hash is: | ||
| 153 | |||
| 154 | ``` | ||
| 155 | 50483743238485412026-0498316314BertonLuchettiXMalebluchetti6ar@taobao.com39 Meadow Ridge TerraceClevelandOH441251964-10-29 | ||
| 156 | ``` | ||
| 157 | |||
| 158 | So, the victim is Berton X. Luchetti, and the flag is `flag{Berton Luchetti}`. | ||
| 159 | |||
| 160 | This challenge would probably have been easier if I was able to use proper SQL | ||
| 161 | commands, but I couldn't do that and standard UNIX tools saved the day. I did | ||
| 162 | the exact same process of parsing the tables for all the other SQL challenges | ||
| 163 | and I found it funny that I solved all of them without needing to run a single | ||
| 164 | SQL command (partly because they didn't load the file). | ||
| 165 | |||
| 166 | ``` \ No newline at end of file | ||
diff --git a/content/blog/kobo_clara-custom-distro.md b/posts/kobo_clara-custom-distro.md index f7d40e1..f32f836 100644 --- a/content/blog/kobo_clara-custom-distro.md +++ b/posts/kobo_clara-custom-distro.md | |||
| @@ -1,8 +1,6 @@ | |||
| 1 | +++ | 1 | title: Kobo Clara HD Custom Linux Distro/RootFS |
| 2 | title = "Kobo Clara HD Custom Linux Distro/RootFS" | 2 | date: 2021-07-22 12:00 |
| 3 | date = 2021-07-22 | 3 | --- |
| 4 | draft = false | ||
| 5 | +++ | ||
| 6 | 4 | ||
| 7 | These are just some notes I made when creating my own mini-distro after | 5 | These are just some notes I made when creating my own mini-distro after |
| 8 | wanting something more custom than just using buildroot or making the | 6 | wanting something more custom than just using buildroot or making the |
| @@ -106,11 +104,13 @@ EDIT 2022-10-21: also gone | |||
| 106 | First I suggest exporting some environment variables to set the | 104 | First I suggest exporting some environment variables to set the |
| 107 | toolchain used as well as enabling static linking and LTO. | 105 | toolchain used as well as enabling static linking and LTO. |
| 108 | 106 | ||
| 109 | export CROSS_COMPILE="arm-linux-musleabihf-" # change to your cross-tc | 107 | ``` |
| 110 | export CC="${CROSS_COMPILE}gcc" | 108 | export CROSS_COMPILE="arm-linux-musleabihf-" # change to your cross-tc |
| 111 | export LDFLAGS="--static" | 109 | export CC="${CROSS_COMPILE}gcc" |
| 112 | export CFLAGS="-flto -static" | 110 | export LDFLAGS="--static" |
| 113 | export ARCH=arm # for compiling the linux kernel | 111 | export CFLAGS="-flto -static" |
| 112 | export ARCH=arm # for compiling the linux kernel | ||
| 113 | ``` | ||
| 114 | 114 | ||
| 115 | To compile toybox, get the source from | 115 | To compile toybox, get the source from |
| 116 | https://landley.net/toybox/downloads/ (or clone the upstream repo). | 116 | https://landley.net/toybox/downloads/ (or clone the upstream repo). |
| @@ -119,23 +119,27 @@ change it as you see fit. Personally, I disabled most of the programs I | |||
| 119 | wouldn't use and kept only the ones that'll help with fixing a problem. | 119 | wouldn't use and kept only the ones that'll help with fixing a problem. |
| 120 | Finally, make sure to run make. | 120 | Finally, make sure to run make. |
| 121 | 121 | ||
| 122 | make defconfig | 122 | ``` |
| 123 | make menuconfig | 123 | make defconfig |
| 124 | make | 124 | make menuconfig |
| 125 | make | ||
| 126 | ``` | ||
| 125 | 127 | ||
| 126 | To move it to your rootfs and set it's symlinks, you could probably run | 128 | To move it to your rootfs and set it's symlinks, you could probably run |
| 127 | make install after setting PREFIX to your rootfs's /bin directory, but | 129 | make install after setting PREFIX to your rootfs's /bin directory, but |
| 128 | I did it manually. | 130 | I did it manually. |
| 129 | 131 | ||
| 130 | # automatic (didn't test, check README) | 132 | ``` |
| 131 | make PREFIX=/path/to/rootfs/bin/ install | 133 | # automatic (didn't test, check README) |
| 134 | make PREFIX=/path/to/rootfs/bin/ install | ||
| 132 | 135 | ||
| 133 | # (semi?) manual | 136 | # (semi?) manual |
| 134 | cp toybox /path/to/rootfs/bin | 137 | cp toybox /path/to/rootfs/bin |
| 135 | 138 | ||
| 136 | # add symlinks if doing manual and you want them | 139 | # add symlinks if doing manual and you want them |
| 137 | cd /path/to/rootfs/bin | 140 | cd /path/to/rootfs/bin |
| 138 | for prog in $(qemu-arm ./toybox); do ln -s toybox "$prog"; done | 141 | for prog in $(qemu-arm ./toybox); do ln -s toybox "$prog"; done |
| 142 | ``` | ||
| 139 | 143 | ||
| 140 | ## dash | 144 | ## dash |
| 141 | Also as of toybox 0.8.5, a shell still isn't included (probably would | 145 | Also as of toybox 0.8.5, a shell still isn't included (probably would |
| @@ -148,20 +152,24 @@ First obtain the source[3] and cd into its | |||
| 148 | untarred directory. Assuming your CC and CFLAGS are set, you can run | 152 | untarred directory. Assuming your CC and CFLAGS are set, you can run |
| 149 | these steps: | 153 | these steps: |
| 150 | 154 | ||
| 151 | autoreconf -fiv | 155 | ``` |
| 152 | ./configure --host=$CROSS_COMPILE --with-libedit | 156 | autoreconf -fiv |
| 153 | make | 157 | ./configure --host=$CROSS_COMPILE --with-libedit |
| 154 | ${CROSS_COMPILE}strip src/dash | 158 | make |
| 159 | ${CROSS_COMPILE}strip src/dash | ||
| 160 | ``` | ||
| 155 | 161 | ||
| 156 | As this is going to be used as the main shell, I've decided to just | 162 | As this is going to be used as the main shell, I've decided to just |
| 157 | copy it to /bin/sh in the rootfs directory, though copying it there but | 163 | copy it to /bin/sh in the rootfs directory, though copying it there but |
| 158 | as /bin/dash and /bin/sh being symlinked to dash is also an option. | 164 | as /bin/dash and /bin/sh being symlinked to dash is also an option. |
| 159 | 165 | ||
| 160 | cp src/dash /path/to/rootfs/bin/sh | 166 | ``` |
| 161 | # or | 167 | cp src/dash /path/to/rootfs/bin/sh |
| 162 | cp src/dash /path/to/rootfs/bin | 168 | # or |
| 163 | cd /path/to/rootfs/bin | 169 | cp src/dash /path/to/rootfs/bin |
| 164 | ln -s dash sh | 170 | cd /path/to/rootfs/bin |
| 171 | ln -s dash sh | ||
| 172 | ``` | ||
| 165 | 173 | ||
| 166 | ## felker's init | 174 | ## felker's init |
| 167 | The init is just a single file that you can get from felker's site[2] | 175 | The init is just a single file that you can get from felker's site[2] |
| @@ -171,8 +179,10 @@ on it so I'd change it to execvp() and remove the third (specifies | |||
| 171 | environment). To compile and install the init, all you need to do is | 179 | environment). To compile and install the init, all you need to do is |
| 172 | run: | 180 | run: |
| 173 | 181 | ||
| 174 | $CC $CFLAGS -o init init.c | 182 | ``` |
| 175 | cp init /path/to/rootfs/sbin | 183 | $CC $CFLAGS -o init init.c |
| 184 | cp init /path/to/rootfs/sbin | ||
| 185 | ``` | ||
| 176 | 186 | ||
| 177 | Instead of /etc/rc being a shell script, you can also make a C program | 187 | Instead of /etc/rc being a shell script, you can also make a C program |
| 178 | that does whatever you think is needed for a proper startup. I'll still | 188 | that does whatever you think is needed for a proper startup. I'll still |
| @@ -187,8 +197,10 @@ able to login to any user. So you'll have to create a file at | |||
| 187 | /path/to/rootfs/etc/passwd. For an empty password to root, you can use | 197 | /path/to/rootfs/etc/passwd. For an empty password to root, you can use |
| 188 | this, though I suggest setting a password as soon as you login: | 198 | this, though I suggest setting a password as soon as you login: |
| 189 | 199 | ||
| 190 | # in rootfs's /etc/passwd | 200 | ``` |
| 191 | root::0:0:root:/root:/bin/sh | 201 | # in rootfs's /etc/passwd |
| 202 | root::0:0:root:/root:/bin/sh | ||
| 203 | ``` | ||
| 192 | 204 | ||
| 193 | With the passwd file created/updated, you should now be able to login | 205 | With the passwd file created/updated, you should now be able to login |
| 194 | to root after the rootfs is copied to your uSD card. Your rootfs so far | 206 | to root after the rootfs is copied to your uSD card. Your rootfs so far |
| @@ -234,8 +246,10 @@ I had a hard time compiling the vendor kernel with many things | |||
| 234 | disabled, so I've kept my config somewhat similar to the default | 246 | disabled, so I've kept my config somewhat similar to the default |
| 235 | config. The config I used is available here (EDIT: dead). | 247 | config. The config I used is available here (EDIT: dead). |
| 236 | 248 | ||
| 237 | make menuconfig | 249 | ``` |
| 238 | make zImage | 250 | make menuconfig |
| 251 | make zImage | ||
| 252 | ``` | ||
| 239 | 253 | ||
| 240 | Assuming it compiles properly and arch/arm/boot/zImage exists, all | 254 | Assuming it compiles properly and arch/arm/boot/zImage exists, all |
| 241 | that's needed to is to write it to your uSD card at the 1M offset. | 255 | that's needed to is to write it to your uSD card at the 1M offset. |
| @@ -246,7 +260,9 @@ I have not done this yet, nor really plan to, but if you do manage to | |||
| 246 | compile the Kobo's vendored u-boot source, then all you'd have to do to | 260 | compile the Kobo's vendored u-boot source, then all you'd have to do to |
| 247 | install it is: | 261 | install it is: |
| 248 | 262 | ||
| 249 | dd if=u-boot-file of=/dev/mmcblk0 bs=128k count=1 seek=6 | 263 | ``` |
| 264 | dd if=u-boot-file of=/dev/mmcblk0 bs=128k count=1 seek=6 | ||
| 265 | ``` | ||
| 250 | 266 | ||
| 251 | If I remember correctly, this command was included in an older | 267 | If I remember correctly, this command was included in an older |
| 252 | firmware's startup script/rcS for updating udev, and it should still | 268 | firmware's startup script/rcS for updating udev, and it should still |
diff --git a/content/blog/kobo_clara-nickel.md b/posts/kobo_clara-nickel.md index 7447283..3dbb068 100644 --- a/content/blog/kobo_clara-nickel.md +++ b/posts/kobo_clara-nickel.md | |||
| @@ -1,9 +1,6 @@ | |||
| 1 | +++ | 1 | title: Kobo Clara HD Notes for Nickel |
| 2 | title = 'Kobo Clara HD Notes for Nickel' | 2 | date: 2021-01-13 12:00 |
| 3 | date = 2021-01-13 | 3 | --- |
| 4 | draft = false | ||
| 5 | layout = "post" | ||
| 6 | +++ | ||
| 7 | 4 | ||
| 8 | My ereader of choice is the Kobo Clara HD and I particularly like it | 5 | My ereader of choice is the Kobo Clara HD and I particularly like it |
| 9 | because my eyes hurt less when reading for long periods of time | 6 | because my eyes hurt less when reading for long periods of time |
diff --git a/content/blog/kobo_clara-plato.md b/posts/kobo_clara-plato.md index b7de110..6e6c72a 100644 --- a/content/blog/kobo_clara-plato.md +++ b/posts/kobo_clara-plato.md | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | +++ | 1 | title: Kobo Clara HD Notes for Plato (and KSM) |
| 2 | title = "Kobo Clara HD Notes for Plato (and KSM)" | 2 | date: 2021-03-27 12:00 |
| 3 | date = 2021-03-27 | 3 | --- |
| 4 | +++ | ||
| 5 | 4 | ||
| 6 | These are my notes for getting Plato on the Kobo Clara HD from scratch | 5 | These are my notes for getting Plato on the Kobo Clara HD from scratch |
| 7 | as well as some notes for getting KSM to work, but I now boot directly | 6 | as well as some notes for getting KSM to work, but I now boot directly |
diff --git a/content/blog/st-bitmap-font-fix.md b/posts/st-bitmap-font-fix.md index 53e6740..dc08b34 100644 --- a/content/blog/st-bitmap-font-fix.md +++ b/posts/st-bitmap-font-fix.md | |||
| @@ -1,8 +1,6 @@ | |||
| 1 | +++ | 1 | title: Fixing bitmap font fallbacks in the st terminal |
| 2 | title = "Fixing bitmap font fallbacks in the st terminal" | 2 | date: 2023-11-24 12:00 |
| 3 | date = 2023-11-24 | 3 | --- |
| 4 | draft = false | ||
| 5 | +++ | ||
| 6 | tldr, change FC_SCALABLE in x.c from 1 to 0. (comes from the font2 patch) | 4 | tldr, change FC_SCALABLE in x.c from 1 to 0. (comes from the font2 patch) |
| 7 | 5 | ||
| 8 | For some context, I have been using xterm for a long while when I'm on OpenBSD | 6 | For some context, I have been using xterm for a long while when I'm on OpenBSD |
diff --git a/content/blog/tmpfilehost.md b/posts/tmpfilehost.md index c8356d8..5249d8e 100644 --- a/content/blog/tmpfilehost.md +++ b/posts/tmpfilehost.md | |||
| @@ -1,8 +1,6 @@ | |||
| 1 | +++ | 1 | title: Creating a Temporary File Hoster |
| 2 | title = "Creating a Temporary File Hoster" | 2 | date: 2022-04-27 12:00 |
| 3 | date = 2022-04-27 | 3 | --- |
| 4 | draft = false | ||
| 5 | +++ | ||
| 6 | For the past couple years, whenever I wanted to upload a file, I would | 4 | For the past couple years, whenever I wanted to upload a file, I would |
| 7 | curl the file to [lainsafe](https://git.qorg11.net/lainsafe.git/), [i/u.kalli.st](https://gt.kalli.st/kallist/uploader), and recently [ttm.sh](https://tildegit.org/tildeverse/ttm.sh). | 5 | curl the file to [lainsafe](https://git.qorg11.net/lainsafe.git/), [i/u.kalli.st](https://gt.kalli.st/kallist/uploader), and recently [ttm.sh](https://tildegit.org/tildeverse/ttm.sh). |
| 8 | 6 | ||
diff --git a/content/blog/vfio-win10.md b/posts/vfio-win10.md index a24b78e..1cd339c 100644 --- a/content/blog/vfio-win10.md +++ b/posts/vfio-win10.md | |||
| @@ -1,8 +1,6 @@ | |||
| 1 | +++ | 1 | title: VFIO Install Notes |
| 2 | title = "VFIO Install Notes" | 2 | date: 2020-10-17 12:00 |
| 3 | date = 2020-10-17 | 3 | --- |
| 4 | draft = false | ||
| 5 | +++ | ||
| 6 | You should first go look at [the Arch Wiki on it](https://wiki.archlinux.org/index.php/PCI%20passthrough%20via%20OVMF) or [Yuri Alek's guide on Single GPU passthrough](https://gitlab.com/YuriAlek/vfio) or [4chan's /g/ wiki on it](https://wiki.installgentoo.com/index.php/PCI_passthrough) as these assume prior knowledge. | 4 | You should first go look at [the Arch Wiki on it](https://wiki.archlinux.org/index.php/PCI%20passthrough%20via%20OVMF) or [Yuri Alek's guide on Single GPU passthrough](https://gitlab.com/YuriAlek/vfio) or [4chan's /g/ wiki on it](https://wiki.installgentoo.com/index.php/PCI_passthrough) as these assume prior knowledge. |
| 7 | 5 | ||
| 8 | # Prerequisites | 6 | # Prerequisites |
diff --git a/posts/workflow_9years.md b/posts/workflow_9years.md new file mode 100644 index 0000000..9a4c24d --- /dev/null +++ b/posts/workflow_9years.md | |||
| @@ -0,0 +1,231 @@ | |||
| 1 | title: *nix workflow after nearly a decade (raw braindump) | ||
| 2 | date: 2026-04-13 12:00 | ||
| 3 | --- | ||
| 4 | |||
| 5 | I was asked a few times from members of my university's cybersecurity | ||
| 6 | club (I was a former e-board member and it's my main club) over the | ||
| 7 | past months of how I use a computer since apparently how I use it is | ||
| 8 | different from how others do it. They also found it fascinating that I | ||
| 9 | used Linux/*BSD for as long as I did, and I'm probably among very few | ||
| 10 | others if any at my university that used it for like 9.5 years. It's | ||
| 11 | organized in what got me into this in the first place, my OS-hopping, | ||
| 12 | my editor-hopping, what my current workflow is, and my (maybe lack of | ||
| 13 | meaningful) thought process behind each switch. The TL;DR of that is | ||
| 14 | I'm like a purist (primarily with the UNIX philosophy) and minimalist | ||
| 15 | (reducing "bloat" as much as possible) and that guided a lot of my | ||
| 16 | decisions up till now at the end of college. Any mistakes I made or | ||
| 17 | any "cringe" I did like being a 4chan `/g/` kid can be blamed on me | ||
| 18 | being 12/13 at the time. The following is the raw braindump before I | ||
| 19 | condensed it into point form. | ||
| 20 | |||
| 21 | --- | ||
| 22 | |||
| 23 | I was introduced to Linux via Luke Smith's early video on why use | ||
| 24 | terminal programs. Then by watching his other videos, I got introduced | ||
| 25 | to stuff like different kinds of distros (he used Parabola at the time | ||
| 26 | and Parabola's wiki in 2017 hadn't removed the beginners guide page | ||
| 27 | unlike Arch wiki, though in hindsight they're basically the same), | ||
| 28 | tiling window managers (i3, dwm), suckless movement and minimalism | ||
| 29 | (was the start of me obsessing over purism even to my detriment | ||
| 30 | sometimes as in spending too much time that I miss deadlines), using | ||
| 31 | LaTeX for documents and presentations, etc. This was during his early | ||
| 32 | days back in 2017 and 2018, before he quit being a linguist professor | ||
| 33 | in Georgia and moved to a cabin in Florida and now complains about les | ||
| 34 | youths. I didn't watch other Linux-related channels until more | ||
| 35 | recently with David Wilson's System Crafters for Emacs and Guix (more | ||
| 36 | on this at the very end, it's a recent change that fundamentally | ||
| 37 | changed how I do stuff, this will come up a lot). | ||
| 38 | |||
| 39 | This put me on the path of both distro-hopping and | ||
| 40 | WM-hopping. Reminder that I started this journey when I was 12 | ||
| 41 | (now 21) so I had lots of time on my hands. I started with Parabola | ||
| 42 | and then switched to Arch shortly after for wifi drivers, then setup | ||
| 43 | Gentoo through reading its handbook to learn about Linux more, and | ||
| 44 | then later did a full LFS+BLFS twice, then CRUX, Sabotage, KISS, | ||
| 45 | Alpine, and then switched between them depending on what little thing | ||
| 46 | annoyed me at the time. Of these, CRUX really made me feel at "home" | ||
| 47 | with giving me just enough packages for a minimal base and I liked | ||
| 48 | being a package maintainer for a short while. I found CRUX through | ||
| 49 | z3bra on the nixers.net forum talking about the differences between it | ||
| 50 | and Gentoo. Sabotage (the way it did stuff was unique and interesting | ||
| 51 | to me at the time but only used for one hop) and KISS (what I wished | ||
| 52 | CRUX was but because it didn't have the drunk tux mascot I didn't use | ||
| 53 | it much beyond a couple hops) from people on IRC and XMPP. I learned a | ||
| 54 | lot about system administration and writing my own packages through | ||
| 55 | distro-hopping. Eventually, the choices converged to Arch (if I wanted | ||
| 56 | something easy), CRUX (because it made me feel fuzzy inside), Gentoo | ||
| 57 | (USE flags put me further on the path of purism, not as much need to | ||
| 58 | maintain so many packages in my overlay unlike CRUX). I later also | ||
| 59 | found out about the BSDs in my goal of more minimalism and purism. It | ||
| 60 | being direct descendants of the venerable Bell Labs's Research | ||
| 61 | UNIX. FreeBSD was what I wished Linux was and I liked its better | ||
| 62 | documentation and integrated first-class ZFS support. OpenBSD I loved | ||
| 63 | for its documentation, focus on security above all else, tight-knit | ||
| 64 | and knowledgeable mature community (unlike with most of Linux), | ||
| 65 | package management feeling more similar to CRUX, mascot, and being | ||
| 66 | Canadian (patriotism I guess). Among the OSes I used the longest | ||
| 67 | without hopping, CRUX, Gentoo, and OpenBSD are the ones I really | ||
| 68 | used. I usually switched away from CRUX due to power user burnout from | ||
| 69 | maintaining packages for adding and making them more minimal, same | ||
| 70 | from Gentoo but to lesser extent due to many other overlays, and from | ||
| 71 | OpenBSD for Windows virtualization at the time and gaming (though I | ||
| 72 | did find out more about FOSS engines and did more retro emulation | ||
| 73 | under OpenBSD). I also had a phase in high school grade 12 with | ||
| 74 | plan9/9front. Really loved the simplicity and elegance of it. Its | ||
| 75 | windowing manager rio/8.5 and acme editor also showed me that mice | ||
| 76 | aren't an inherently bad thing for computer use when designed | ||
| 77 | properly. I couldn't go further with dailying it because my i219-v and | ||
| 78 | r8168 driver wasn't working properly even after I tried patching it | ||
| 79 | with my then meager C skills. Later in college around junior year, I | ||
| 80 | was peer pressured into NixOS from my functional programming | ||
| 81 | friends. I liked the idea behind it and it made systemd somewhat | ||
| 82 | usable, but I disliked the special snowflake DSL (they should have | ||
| 83 | used something else as a base like Haskell or anything else they took | ||
| 84 | inspiration from) and it liked pulling in all sorts of transient | ||
| 85 | dependencies, the exact opposite of what I wanted in Linux since I | ||
| 86 | started using it years ago. What really put me off more than transient | ||
| 87 | deps was poor and inconsistent documentation (like pretty much nothing | ||
| 88 | about flakes: there was a disconnect in documentation of what the | ||
| 89 | broader community used and what upstream deemed stable). But, it had | ||
| 90 | advantages like helping organize my system+home configs and dotfiles | ||
| 91 | all in one place which was very nice. So I briefly tried Guix, but | ||
| 92 | once again without knowing its language was hard to use and also | ||
| 93 | trying to mould my existing suckless+vi non-emacs worklow into it was | ||
| 94 | hard at the time. So I once again switched back and forth between | ||
| 95 | Arch, CRUX, Gentoo, and NixOS despite their shortcomings I detailed | ||
| 96 | earlier: my power user burnout or getting bored. Continuing later for | ||
| 97 | recent switch to Guix+Emacs. | ||
| 98 | |||
| 99 | So now about window manager choice. I started with i3 since that's | ||
| 100 | what Luke Smith used and I was curious about how a keyboard-only | ||
| 101 | workflow would look like. It's also what the most popular WM on | ||
| 102 | r/unixporn was. Back in the day when pretty much every post there was | ||
| 103 | either a close-to-default i3-gaps setup or bspwm instead of sway and | ||
| 104 | hyprland now. I then switched to bspwm because it was more minimal and | ||
| 105 | UNIX philosophy like where it split keybind handling into separate | ||
| 106 | program sxhkd. I also used herbstluftwm, the manual tiling was | ||
| 107 | nice. Then comes dwm, my main WM of choice for a long time since it | ||
| 108 | blended minimalism with functionality and also by suckless so was | ||
| 109 | elegant. However, I still did end up switching to spectrwm since it | ||
| 110 | looked similar visually but I found it easier to config. According to | ||
| 111 | my screenshots though, that didn't last for long. I think I only | ||
| 112 | stayed on it for a few months before switching back to dwm. I did | ||
| 113 | briefly try out sway to see if Wayland was really all that great, but | ||
| 114 | ultimately switched back to dwm again, and only really used it when I | ||
| 115 | felt too lazy to setup Xorg on a new system and not using my | ||
| 116 | pre-existing configs. Again, continuing later for my recent switch to | ||
| 117 | Guix+Emacs. | ||
| 118 | |||
| 119 | Missing what editor I used is criminal for this kind of topic. Going | ||
| 120 | back to before Linux, I used Eclipse for Java and Notepad++ for | ||
| 121 | regular stuff, and then I think I used Atom for a brief period of time | ||
| 122 | (VS Code wasn't out yet or something in 2016/17). I didn't do much | ||
| 123 | programming back then, partly because getting dependencies and | ||
| 124 | compiling anything is a pain if my experience with compiling aseprite | ||
| 125 | (sprite editor with cmake buildsystem) was anything to go off of. When | ||
| 126 | I started using Linux, I also started with Vim. Programs like it were | ||
| 127 | what got me to switch in the first place. Turns out learning your | ||
| 128 | tools is important (and that comes up a lot). Even back then I didn't | ||
| 129 | like using much of the pre-made configs, they were bloated and harder | ||
| 130 | to reason about as a new user since defaults were changed. Also had a | ||
| 131 | brief stint with Emacs, but not knowing basic Lisp made it hard to | ||
| 132 | "know" it and it was bloated (common joke is it's an operating system | ||
| 133 | that lacks a good editor) and also not optimized on Windows (same | ||
| 134 | config from Linux) where it was just noticeably more sluggish on muh | ||
| 135 | gamin' laptop when running Win10 instead of like Arch or Gentoo. After | ||
| 136 | learning Vim enough like how to move easily and basic ex commands, I | ||
| 137 | of course wanted more minimalism. Had a nice time with vis and nvi, | ||
| 138 | used them for a while. In my plan9 phase, I used acme briefly and | ||
| 139 | learned a lot about sam through its manual, which also taught me how | ||
| 140 | to use ed the standard text editor, which also taught me (basic) regex | ||
| 141 | which I can't overstate how much better it made editing files in | ||
| 142 | addition to vi motions. | ||
| 143 | |||
| 144 | Finally, my current workflow and choices. It's now all based around | ||
| 145 | Lisp and Scheme because they make me feel all fuzzy inside when | ||
| 146 | learning it, just like I did when learning to use Linux in middle | ||
| 147 | school and how to program in C. The propaganda that got me into using | ||
| 148 | this now was when I heard about the Lispy Gopher Show when I was | ||
| 149 | briefly on the Fediverse through Prahou (the author/artist of | ||
| 150 | unix_surrealism from analog_nowhere). While I did briefly use Emacs in | ||
| 151 | the past, I did not learn it properly. As in, not knowing Lisp meant I | ||
| 152 | needed to look a lot of things up instead of just writing them | ||
| 153 | myself. Technically with the vi-like editors, I also didn't write | ||
| 154 | scripts in them nor needed to touch their config due to how minimal | ||
| 155 | they already were by default and that regex+vi-motions going a long | ||
| 156 | way and there being packages to bridge the remaining gap for | ||
| 157 | integrations. But with Emacs, the parentheses I guess made it more | ||
| 158 | daunting or something. This sort of mirrors what I did when I first | ||
| 159 | got into Linux (well Arch) as I read a lot through its wiki. But | ||
| 160 | compared to just regular system administration where you run a bunch | ||
| 161 | of commands or even making your own distro via LFS, I guess properly | ||
| 162 | learning an editor and its programming language was too much for me at | ||
| 163 | the time. For new Emacs users, it was also recommended a lot that they | ||
| 164 | use a pre-made opinionated config like Doom-Emacs or Spacemacs (neovim | ||
| 165 | has a similar situation) and that really put me off since that felt | ||
| 166 | like I would be learning instead how those work instead of the editor | ||
| 167 | itself. Now that I know some functional programming through OCaml and | ||
| 168 | to some extent Nix from a couple summers ago, learning Lisp and Scheme | ||
| 169 | was actually much easier. Compared to using a vi-like editor, using | ||
| 170 | Emacs seemed nicer for working with these kinds of languages since I | ||
| 171 | can selectively execute parts of a program, simliar to something like | ||
| 172 | Jupyter notebook without it being so web- and Python-focused and being | ||
| 173 | an inefficient use of system resources. The main reason why I did not | ||
| 174 | want to use Emacs previously was that it seemed like a monolithic | ||
| 175 | kitchen sink of everything. I think it being described as an operating | ||
| 176 | system within an operating system isn't too much of an inaccurate | ||
| 177 | description. However, compared to Linux and Xorg proper where I tried | ||
| 178 | following minimalism and the UNIX philosophy as much as I could | ||
| 179 | (i.e. small, minimal, self-contained programs for a specific task), | ||
| 180 | there was not much cohesion between them. At most, they'll have | ||
| 181 | vi-keybinds and happen to use ncurses but the layout of everything | ||
| 182 | looks different and configured with different syntaxes (e.g. mutt the | ||
| 183 | mail client looks different from newsboat the RSS reader and different | ||
| 184 | from lynx and links2). Meanwhile with Emacs, yes there are multiple | ||
| 185 | packages and yes I'm not necessarily using POSIX shell scripts for | ||
| 186 | connecting things together, but Lisp is a more powerful language than | ||
| 187 | something like shell that depends on other programs (written in other | ||
| 188 | languages) to do even simple stuff. With Emacs, I now have everything | ||
| 189 | integrated into a single program, everything properly goes through | ||
| 190 | text-based buffers, and as a result is even easier to integrate around | ||
| 191 | because everything is primarily text. Also previously, some popular | ||
| 192 | packages that people use also seemed like it may have contributed to | ||
| 193 | Emacs's bloat in my point of view at that time like /needing/ | ||
| 194 | something like ivy or helm. There's better packages available that do | ||
| 195 | the same thing now, like orderless (for fuzzy searching) combined with | ||
| 196 | vertico (for the vertical complete menu that ivy gave), and consult | ||
| 197 | for better autocomplete for various existing Emacs functions, among | ||
| 198 | other stuff. Now it's my main editor since like last summerish, and I | ||
| 199 | configured it to be my editor, Scheme programming via Geiser, Lisp via | ||
| 200 | just Emacs (since for now I'm mainly using Emacs Lisp and not Common | ||
| 201 | Lisp+SLIME) and using the eval-* functions a lot (for both Lisp and | ||
| 202 | Scheme), document editing and task planning and habit tracking through | ||
| 203 | org-mode (some people use Emacs just for org-mode since it's much more | ||
| 204 | than just a markup language), email through notmuch+mbsync+msmtp | ||
| 205 | (stayed pretty much the same except I'm using notmuch.el directly | ||
| 206 | instead of through like mutt or aerc), RSS through elfeed, browsing | ||
| 207 | primarily through eww (though I have to use qutebrowser for js-heavy | ||
| 208 | sites like Canvas), document viewing through pdftools and docview | ||
| 209 | instead of through mupdf (though for some larger PDFs like textbooks, | ||
| 210 | mupdf is just faster but not needed for most of my PDFs), backgrounded | ||
| 211 | programs through dtach and its associated emacs management package | ||
| 212 | instead of tmux, gptel for interacting with my local LLMs running on | ||
| 213 | my desktop through vllm, and finally as my X window manager via EXWM | ||
| 214 | instead of dwm or any other WM I used to use in the past. Works well | ||
| 215 | when playing games too like Elite Dangerous, Emacs doesn't get in the | ||
| 216 | way. | ||
| 217 | |||
| 218 | I know this was very ramble-y. I just braindumped since there's so | ||
| 219 | much to cover and a lot of stuff to remember over the past 9 years | ||
| 220 | that I couldn't think in a more organized way without having all of it | ||
| 221 | written down. I probably missed some stuff, so any questions? | ||
| 222 | |||
| 223 | --- | ||
| 224 | |||
| 225 | In the actual presentation, I missed mentioning my peripherals (a | ||
| 226 | Ferris Sweep with Kailh Choc Ambient Nocturnal switches for laptop, | ||
| 227 | Corne with Zealios Zilent v2 switches for my desktop, and a Ploopy | ||
| 228 | Adept as my mouse for both) as well since that's also different from | ||
| 229 | how most people use it, as well as my current project "X380", a modded | ||
| 230 | stripped-down X280 (I'll make a post when it's more finalized after | ||
| 231 | fixing my 3D printer). | ||
diff --git a/static/agpl-3.0.txt b/static/agpl-3.0.txt new file mode 100644 index 0000000..be3f7b2 --- /dev/null +++ b/static/agpl-3.0.txt | |||
| @@ -0,0 +1,661 @@ | |||
| 1 | GNU AFFERO GENERAL PUBLIC LICENSE | ||
| 2 | Version 3, 19 November 2007 | ||
| 3 | |||
| 4 | Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> | ||
| 5 | Everyone is permitted to copy and distribute verbatim copies | ||
| 6 | of this license document, but changing it is not allowed. | ||
| 7 | |||
| 8 | Preamble | ||
| 9 | |||
| 10 | The GNU Affero General Public License is a free, copyleft license for | ||
| 11 | software and other kinds of works, specifically designed to ensure | ||
| 12 | cooperation with the community in the case of network server software. | ||
| 13 | |||
| 14 | The licenses for most software and other practical works are designed | ||
| 15 | to take away your freedom to share and change the works. By contrast, | ||
| 16 | our General Public Licenses are intended to guarantee your freedom to | ||
| 17 | share and change all versions of a program--to make sure it remains free | ||
| 18 | software for all its users. | ||
| 19 | |||
| 20 | When we speak of free software, we are referring to freedom, not | ||
| 21 | price. Our General Public Licenses are designed to make sure that you | ||
| 22 | have the freedom to distribute copies of free software (and charge for | ||
| 23 | them if you wish), that you receive source code or can get it if you | ||
| 24 | want it, that you can change the software or use pieces of it in new | ||
| 25 | free programs, and that you know you can do these things. | ||
| 26 | |||
| 27 | Developers that use our General Public Licenses protect your rights | ||
| 28 | with two steps: (1) assert copyright on the software, and (2) offer | ||
| 29 | you this License which gives you legal permission to copy, distribute | ||
| 30 | and/or modify the software. | ||
| 31 | |||
| 32 | A secondary benefit of defending all users' freedom is that | ||
| 33 | improvements made in alternate versions of the program, if they | ||
| 34 | receive widespread use, become available for other developers to | ||
| 35 | incorporate. Many developers of free software are heartened and | ||
| 36 | encouraged by the resulting cooperation. However, in the case of | ||
| 37 | software used on network servers, this result may fail to come about. | ||
| 38 | The GNU General Public License permits making a modified version and | ||
| 39 | letting the public access it on a server without ever releasing its | ||
| 40 | source code to the public. | ||
| 41 | |||
| 42 | The GNU Affero General Public License is designed specifically to | ||
| 43 | ensure that, in such cases, the modified source code becomes available | ||
| 44 | to the community. It requires the operator of a network server to | ||
| 45 | provide the source code of the modified version running there to the | ||
| 46 | users of that server. Therefore, public use of a modified version, on | ||
| 47 | a publicly accessible server, gives the public access to the source | ||
| 48 | code of the modified version. | ||
| 49 | |||
| 50 | An older license, called the Affero General Public License and | ||
| 51 | published by Affero, was designed to accomplish similar goals. This is | ||
| 52 | a different license, not a version of the Affero GPL, but Affero has | ||
| 53 | released a new version of the Affero GPL which permits relicensing under | ||
| 54 | this license. | ||
| 55 | |||
| 56 | The precise terms and conditions for copying, distribution and | ||
| 57 | modification follow. | ||
| 58 | |||
| 59 | TERMS AND CONDITIONS | ||
| 60 | |||
| 61 | 0. Definitions. | ||
| 62 | |||
| 63 | "This License" refers to version 3 of the GNU Affero General Public License. | ||
| 64 | |||
| 65 | "Copyright" also means copyright-like laws that apply to other kinds of | ||
| 66 | works, such as semiconductor masks. | ||
| 67 | |||
| 68 | "The Program" refers to any copyrightable work licensed under this | ||
| 69 | License. Each licensee is addressed as "you". "Licensees" and | ||
| 70 | "recipients" may be individuals or organizations. | ||
| 71 | |||
| 72 | To "modify" a work means to copy from or adapt all or part of the work | ||
| 73 | in a fashion requiring copyright permission, other than the making of an | ||
| 74 | exact copy. The resulting work is called a "modified version" of the | ||
| 75 | earlier work or a work "based on" the earlier work. | ||
| 76 | |||
| 77 | A "covered work" means either the unmodified Program or a work based | ||
| 78 | on the Program. | ||
| 79 | |||
| 80 | To "propagate" a work means to do anything with it that, without | ||
| 81 | permission, would make you directly or secondarily liable for | ||
| 82 | infringement under applicable copyright law, except executing it on a | ||
| 83 | computer or modifying a private copy. Propagation includes copying, | ||
| 84 | distribution (with or without modification), making available to the | ||
| 85 | public, and in some countries other activities as well. | ||
| 86 | |||
| 87 | To "convey" a work means any kind of propagation that enables other | ||
| 88 | parties to make or receive copies. Mere interaction with a user through | ||
| 89 | a computer network, with no transfer of a copy, is not conveying. | ||
| 90 | |||
| 91 | An interactive user interface displays "Appropriate Legal Notices" | ||
| 92 | to the extent that it includes a convenient and prominently visible | ||
| 93 | feature that (1) displays an appropriate copyright notice, and (2) | ||
| 94 | tells the user that there is no warranty for the work (except to the | ||
| 95 | extent that warranties are provided), that licensees may convey the | ||
| 96 | work under this License, and how to view a copy of this License. If | ||
| 97 | the interface presents a list of user commands or options, such as a | ||
| 98 | menu, a prominent item in the list meets this criterion. | ||
| 99 | |||
| 100 | 1. Source Code. | ||
| 101 | |||
| 102 | The "source code" for a work means the preferred form of the work | ||
| 103 | for making modifications to it. "Object code" means any non-source | ||
| 104 | form of a work. | ||
| 105 | |||
| 106 | A "Standard Interface" means an interface that either is an official | ||
| 107 | standard defined by a recognized standards body, or, in the case of | ||
| 108 | interfaces specified for a particular programming language, one that | ||
| 109 | is widely used among developers working in that language. | ||
| 110 | |||
| 111 | The "System Libraries" of an executable work include anything, other | ||
| 112 | than the work as a whole, that (a) is included in the normal form of | ||
| 113 | packaging a Major Component, but which is not part of that Major | ||
| 114 | Component, and (b) serves only to enable use of the work with that | ||
| 115 | Major Component, or to implement a Standard Interface for which an | ||
| 116 | implementation is available to the public in source code form. A | ||
| 117 | "Major Component", in this context, means a major essential component | ||
| 118 | (kernel, window system, and so on) of the specific operating system | ||
| 119 | (if any) on which the executable work runs, or a compiler used to | ||
| 120 | produce the work, or an object code interpreter used to run it. | ||
| 121 | |||
| 122 | The "Corresponding Source" for a work in object code form means all | ||
| 123 | the source code needed to generate, install, and (for an executable | ||
| 124 | work) run the object code and to modify the work, including scripts to | ||
| 125 | control those activities. However, it does not include the work's | ||
| 126 | System Libraries, or general-purpose tools or generally available free | ||
| 127 | programs which are used unmodified in performing those activities but | ||
| 128 | which are not part of the work. For example, Corresponding Source | ||
| 129 | includes interface definition files associated with source files for | ||
| 130 | the work, and the source code for shared libraries and dynamically | ||
| 131 | linked subprograms that the work is specifically designed to require, | ||
| 132 | such as by intimate data communication or control flow between those | ||
| 133 | subprograms and other parts of the work. | ||
| 134 | |||
| 135 | The Corresponding Source need not include anything that users | ||
| 136 | can regenerate automatically from other parts of the Corresponding | ||
| 137 | Source. | ||
| 138 | |||
| 139 | The Corresponding Source for a work in source code form is that | ||
| 140 | same work. | ||
| 141 | |||
| 142 | 2. Basic Permissions. | ||
| 143 | |||
| 144 | All rights granted under this License are granted for the term of | ||
| 145 | copyright on the Program, and are irrevocable provided the stated | ||
| 146 | conditions are met. This License explicitly affirms your unlimited | ||
| 147 | permission to run the unmodified Program. The output from running a | ||
| 148 | covered work is covered by this License only if the output, given its | ||
| 149 | content, constitutes a covered work. This License acknowledges your | ||
| 150 | rights of fair use or other equivalent, as provided by copyright law. | ||
| 151 | |||
| 152 | You may make, run and propagate covered works that you do not | ||
| 153 | convey, without conditions so long as your license otherwise remains | ||
| 154 | in force. You may convey covered works to others for the sole purpose | ||
| 155 | of having them make modifications exclusively for you, or provide you | ||
| 156 | with facilities for running those works, provided that you comply with | ||
| 157 | the terms of this License in conveying all material for which you do | ||
| 158 | not control copyright. Those thus making or running the covered works | ||
| 159 | for you must do so exclusively on your behalf, under your direction | ||
| 160 | and control, on terms that prohibit them from making any copies of | ||
| 161 | your copyrighted material outside their relationship with you. | ||
| 162 | |||
| 163 | Conveying under any other circumstances is permitted solely under | ||
| 164 | the conditions stated below. Sublicensing is not allowed; section 10 | ||
| 165 | makes it unnecessary. | ||
| 166 | |||
| 167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. | ||
| 168 | |||
| 169 | No covered work shall be deemed part of an effective technological | ||
| 170 | measure under any applicable law fulfilling obligations under article | ||
| 171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or | ||
| 172 | similar laws prohibiting or restricting circumvention of such | ||
| 173 | measures. | ||
| 174 | |||
| 175 | When you convey a covered work, you waive any legal power to forbid | ||
| 176 | circumvention of technological measures to the extent such circumvention | ||
| 177 | is effected by exercising rights under this License with respect to | ||
| 178 | the covered work, and you disclaim any intention to limit operation or | ||
| 179 | modification of the work as a means of enforcing, against the work's | ||
| 180 | users, your or third parties' legal rights to forbid circumvention of | ||
| 181 | technological measures. | ||
| 182 | |||
| 183 | 4. Conveying Verbatim Copies. | ||
| 184 | |||
| 185 | You may convey verbatim copies of the Program's source code as you | ||
| 186 | receive it, in any medium, provided that you conspicuously and | ||
| 187 | appropriately publish on each copy an appropriate copyright notice; | ||
| 188 | keep intact all notices stating that this License and any | ||
| 189 | non-permissive terms added in accord with section 7 apply to the code; | ||
| 190 | keep intact all notices of the absence of any warranty; and give all | ||
| 191 | recipients a copy of this License along with the Program. | ||
| 192 | |||
| 193 | You may charge any price or no price for each copy that you convey, | ||
| 194 | and you may offer support or warranty protection for a fee. | ||
| 195 | |||
| 196 | 5. Conveying Modified Source Versions. | ||
| 197 | |||
| 198 | You may convey a work based on the Program, or the modifications to | ||
| 199 | produce it from the Program, in the form of source code under the | ||
| 200 | terms of section 4, provided that you also meet all of these conditions: | ||
| 201 | |||
| 202 | a) The work must carry prominent notices stating that you modified | ||
| 203 | it, and giving a relevant date. | ||
| 204 | |||
| 205 | b) The work must carry prominent notices stating that it is | ||
| 206 | released under this License and any conditions added under section | ||
| 207 | 7. This requirement modifies the requirement in section 4 to | ||
| 208 | "keep intact all notices". | ||
| 209 | |||
| 210 | c) You must license the entire work, as a whole, under this | ||
| 211 | License to anyone who comes into possession of a copy. This | ||
| 212 | License will therefore apply, along with any applicable section 7 | ||
| 213 | additional terms, to the whole of the work, and all its parts, | ||
| 214 | regardless of how they are packaged. This License gives no | ||
| 215 | permission to license the work in any other way, but it does not | ||
| 216 | invalidate such permission if you have separately received it. | ||
| 217 | |||
| 218 | d) If the work has interactive user interfaces, each must display | ||
| 219 | Appropriate Legal Notices; however, if the Program has interactive | ||
| 220 | interfaces that do not display Appropriate Legal Notices, your | ||
| 221 | work need not make them do so. | ||
| 222 | |||
| 223 | A compilation of a covered work with other separate and independent | ||
| 224 | works, which are not by their nature extensions of the covered work, | ||
| 225 | and which are not combined with it such as to form a larger program, | ||
| 226 | in or on a volume of a storage or distribution medium, is called an | ||
| 227 | "aggregate" if the compilation and its resulting copyright are not | ||
| 228 | used to limit the access or legal rights of the compilation's users | ||
| 229 | beyond what the individual works permit. Inclusion of a covered work | ||
| 230 | in an aggregate does not cause this License to apply to the other | ||
| 231 | parts of the aggregate. | ||
| 232 | |||
| 233 | 6. Conveying Non-Source Forms. | ||
| 234 | |||
| 235 | You may convey a covered work in object code form under the terms | ||
| 236 | of sections 4 and 5, provided that you also convey the | ||
| 237 | machine-readable Corresponding Source under the terms of this License, | ||
| 238 | in one of these ways: | ||
| 239 | |||
| 240 | a) Convey the object code in, or embodied in, a physical product | ||
| 241 | (including a physical distribution medium), accompanied by the | ||
| 242 | Corresponding Source fixed on a durable physical medium | ||
| 243 | customarily used for software interchange. | ||
| 244 | |||
| 245 | b) Convey the object code in, or embodied in, a physical product | ||
| 246 | (including a physical distribution medium), accompanied by a | ||
| 247 | written offer, valid for at least three years and valid for as | ||
| 248 | long as you offer spare parts or customer support for that product | ||
| 249 | model, to give anyone who possesses the object code either (1) a | ||
| 250 | copy of the Corresponding Source for all the software in the | ||
| 251 | product that is covered by this License, on a durable physical | ||
| 252 | medium customarily used for software interchange, for a price no | ||
| 253 | more than your reasonable cost of physically performing this | ||
| 254 | conveying of source, or (2) access to copy the | ||
| 255 | Corresponding Source from a network server at no charge. | ||
| 256 | |||
| 257 | c) Convey individual copies of the object code with a copy of the | ||
| 258 | written offer to provide the Corresponding Source. This | ||
| 259 | alternative is allowed only occasionally and noncommercially, and | ||
| 260 | only if you received the object code with such an offer, in accord | ||
| 261 | with subsection 6b. | ||
| 262 | |||
| 263 | d) Convey the object code by offering access from a designated | ||
| 264 | place (gratis or for a charge), and offer equivalent access to the | ||
| 265 | Corresponding Source in the same way through the same place at no | ||
| 266 | further charge. You need not require recipients to copy the | ||
| 267 | Corresponding Source along with the object code. If the place to | ||
| 268 | copy the object code is a network server, the Corresponding Source | ||
| 269 | may be on a different server (operated by you or a third party) | ||
| 270 | that supports equivalent copying facilities, provided you maintain | ||
| 271 | clear directions next to the object code saying where to find the | ||
| 272 | Corresponding Source. Regardless of what server hosts the | ||
| 273 | Corresponding Source, you remain obligated to ensure that it is | ||
| 274 | available for as long as needed to satisfy these requirements. | ||
| 275 | |||
| 276 | e) Convey the object code using peer-to-peer transmission, provided | ||
| 277 | you inform other peers where the object code and Corresponding | ||
| 278 | Source of the work are being offered to the general public at no | ||
| 279 | charge under subsection 6d. | ||
| 280 | |||
| 281 | A separable portion of the object code, whose source code is excluded | ||
| 282 | from the Corresponding Source as a System Library, need not be | ||
| 283 | included in conveying the object code work. | ||
| 284 | |||
| 285 | A "User Product" is either (1) a "consumer product", which means any | ||
| 286 | tangible personal property which is normally used for personal, family, | ||
| 287 | or household purposes, or (2) anything designed or sold for incorporation | ||
| 288 | into a dwelling. In determining whether a product is a consumer product, | ||
| 289 | doubtful cases shall be resolved in favor of coverage. For a particular | ||
| 290 | product received by a particular user, "normally used" refers to a | ||
| 291 | typical or common use of that class of product, regardless of the status | ||
| 292 | of the particular user or of the way in which the particular user | ||
| 293 | actually uses, or expects or is expected to use, the product. A product | ||
| 294 | is a consumer product regardless of whether the product has substantial | ||
| 295 | commercial, industrial or non-consumer uses, unless such uses represent | ||
| 296 | the only significant mode of use of the product. | ||
| 297 | |||
| 298 | "Installation Information" for a User Product means any methods, | ||
| 299 | procedures, authorization keys, or other information required to install | ||
| 300 | and execute modified versions of a covered work in that User Product from | ||
| 301 | a modified version of its Corresponding Source. The information must | ||
| 302 | suffice to ensure that the continued functioning of the modified object | ||
| 303 | code is in no case prevented or interfered with solely because | ||
| 304 | modification has been made. | ||
| 305 | |||
| 306 | If you convey an object code work under this section in, or with, or | ||
| 307 | specifically for use in, a User Product, and the conveying occurs as | ||
| 308 | part of a transaction in which the right of possession and use of the | ||
| 309 | User Product is transferred to the recipient in perpetuity or for a | ||
| 310 | fixed term (regardless of how the transaction is characterized), the | ||
| 311 | Corresponding Source conveyed under this section must be accompanied | ||
| 312 | by the Installation Information. But this requirement does not apply | ||
| 313 | if neither you nor any third party retains the ability to install | ||
| 314 | modified object code on the User Product (for example, the work has | ||
| 315 | been installed in ROM). | ||
| 316 | |||
| 317 | The requirement to provide Installation Information does not include a | ||
| 318 | requirement to continue to provide support service, warranty, or updates | ||
| 319 | for a work that has been modified or installed by the recipient, or for | ||
| 320 | the User Product in which it has been modified or installed. Access to a | ||
| 321 | network may be denied when the modification itself materially and | ||
| 322 | adversely affects the operation of the network or violates the rules and | ||
| 323 | protocols for communication across the network. | ||
| 324 | |||
| 325 | Corresponding Source conveyed, and Installation Information provided, | ||
| 326 | in accord with this section must be in a format that is publicly | ||
| 327 | documented (and with an implementation available to the public in | ||
| 328 | source code form), and must require no special password or key for | ||
| 329 | unpacking, reading or copying. | ||
| 330 | |||
| 331 | 7. Additional Terms. | ||
| 332 | |||
| 333 | "Additional permissions" are terms that supplement the terms of this | ||
| 334 | License by making exceptions from one or more of its conditions. | ||
| 335 | Additional permissions that are applicable to the entire Program shall | ||
| 336 | be treated as though they were included in this License, to the extent | ||
| 337 | that they are valid under applicable law. If additional permissions | ||
| 338 | apply only to part of the Program, that part may be used separately | ||
| 339 | under those permissions, but the entire Program remains governed by | ||
| 340 | this License without regard to the additional permissions. | ||
| 341 | |||
| 342 | When you convey a copy of a covered work, you may at your option | ||
| 343 | remove any additional permissions from that copy, or from any part of | ||
| 344 | it. (Additional permissions may be written to require their own | ||
| 345 | removal in certain cases when you modify the work.) You may place | ||
| 346 | additional permissions on material, added by you to a covered work, | ||
| 347 | for which you have or can give appropriate copyright permission. | ||
| 348 | |||
| 349 | Notwithstanding any other provision of this License, for material you | ||
| 350 | add to a covered work, you may (if authorized by the copyright holders of | ||
| 351 | that material) supplement the terms of this License with terms: | ||
| 352 | |||
| 353 | a) Disclaiming warranty or limiting liability differently from the | ||
| 354 | terms of sections 15 and 16 of this License; or | ||
| 355 | |||
| 356 | b) Requiring preservation of specified reasonable legal notices or | ||
| 357 | author attributions in that material or in the Appropriate Legal | ||
| 358 | Notices displayed by works containing it; or | ||
| 359 | |||
| 360 | c) Prohibiting misrepresentation of the origin of that material, or | ||
| 361 | requiring that modified versions of such material be marked in | ||
| 362 | reasonable ways as different from the original version; or | ||
| 363 | |||
| 364 | d) Limiting the use for publicity purposes of names of licensors or | ||
| 365 | authors of the material; or | ||
| 366 | |||
| 367 | e) Declining to grant rights under trademark law for use of some | ||
| 368 | trade names, trademarks, or service marks; or | ||
| 369 | |||
| 370 | f) Requiring indemnification of licensors and authors of that | ||
| 371 | material by anyone who conveys the material (or modified versions of | ||
| 372 | it) with contractual assumptions of liability to the recipient, for | ||
| 373 | any liability that these contractual assumptions directly impose on | ||
| 374 | those licensors and authors. | ||
| 375 | |||
| 376 | All other non-permissive additional terms are considered "further | ||
| 377 | restrictions" within the meaning of section 10. If the Program as you | ||
| 378 | received it, or any part of it, contains a notice stating that it is | ||
| 379 | governed by this License along with a term that is a further | ||
| 380 | restriction, you may remove that term. If a license document contains | ||
| 381 | a further restriction but permits relicensing or conveying under this | ||
| 382 | License, you may add to a covered work material governed by the terms | ||
| 383 | of that license document, provided that the further restriction does | ||
| 384 | not survive such relicensing or conveying. | ||
| 385 | |||
| 386 | If you add terms to a covered work in accord with this section, you | ||
| 387 | must place, in the relevant source files, a statement of the | ||
| 388 | additional terms that apply to those files, or a notice indicating | ||
| 389 | where to find the applicable terms. | ||
| 390 | |||
| 391 | Additional terms, permissive or non-permissive, may be stated in the | ||
| 392 | form of a separately written license, or stated as exceptions; | ||
| 393 | the above requirements apply either way. | ||
| 394 | |||
| 395 | 8. Termination. | ||
| 396 | |||
| 397 | You may not propagate or modify a covered work except as expressly | ||
| 398 | provided under this License. Any attempt otherwise to propagate or | ||
| 399 | modify it is void, and will automatically terminate your rights under | ||
| 400 | this License (including any patent licenses granted under the third | ||
| 401 | paragraph of section 11). | ||
| 402 | |||
| 403 | However, if you cease all violation of this License, then your | ||
| 404 | license from a particular copyright holder is reinstated (a) | ||
| 405 | provisionally, unless and until the copyright holder explicitly and | ||
| 406 | finally terminates your license, and (b) permanently, if the copyright | ||
| 407 | holder fails to notify you of the violation by some reasonable means | ||
| 408 | prior to 60 days after the cessation. | ||
| 409 | |||
| 410 | Moreover, your license from a particular copyright holder is | ||
| 411 | reinstated permanently if the copyright holder notifies you of the | ||
| 412 | violation by some reasonable means, this is the first time you have | ||
| 413 | received notice of violation of this License (for any work) from that | ||
| 414 | copyright holder, and you cure the violation prior to 30 days after | ||
| 415 | your receipt of the notice. | ||
| 416 | |||
| 417 | Termination of your rights under this section does not terminate the | ||
| 418 | licenses of parties who have received copies or rights from you under | ||
| 419 | this License. If your rights have been terminated and not permanently | ||
| 420 | reinstated, you do not qualify to receive new licenses for the same | ||
| 421 | material under section 10. | ||
| 422 | |||
| 423 | 9. Acceptance Not Required for Having Copies. | ||
| 424 | |||
| 425 | You are not required to accept this License in order to receive or | ||
| 426 | run a copy of the Program. Ancillary propagation of a covered work | ||
| 427 | occurring solely as a consequence of using peer-to-peer transmission | ||
| 428 | to receive a copy likewise does not require acceptance. However, | ||
| 429 | nothing other than this License grants you permission to propagate or | ||
| 430 | modify any covered work. These actions infringe copyright if you do | ||
| 431 | not accept this License. Therefore, by modifying or propagating a | ||
| 432 | covered work, you indicate your acceptance of this License to do so. | ||
| 433 | |||
| 434 | 10. Automatic Licensing of Downstream Recipients. | ||
| 435 | |||
| 436 | Each time you convey a covered work, the recipient automatically | ||
| 437 | receives a license from the original licensors, to run, modify and | ||
| 438 | propagate that work, subject to this License. You are not responsible | ||
| 439 | for enforcing compliance by third parties with this License. | ||
| 440 | |||
| 441 | An "entity transaction" is a transaction transferring control of an | ||
| 442 | organization, or substantially all assets of one, or subdividing an | ||
| 443 | organization, or merging organizations. If propagation of a covered | ||
| 444 | work results from an entity transaction, each party to that | ||
| 445 | transaction who receives a copy of the work also receives whatever | ||
| 446 | licenses to the work the party's predecessor in interest had or could | ||
| 447 | give under the previous paragraph, plus a right to possession of the | ||
| 448 | Corresponding Source of the work from the predecessor in interest, if | ||
| 449 | the predecessor has it or can get it with reasonable efforts. | ||
| 450 | |||
| 451 | You may not impose any further restrictions on the exercise of the | ||
| 452 | rights granted or affirmed under this License. For example, you may | ||
| 453 | not impose a license fee, royalty, or other charge for exercise of | ||
| 454 | rights granted under this License, and you may not initiate litigation | ||
| 455 | (including a cross-claim or counterclaim in a lawsuit) alleging that | ||
| 456 | any patent claim is infringed by making, using, selling, offering for | ||
| 457 | sale, or importing the Program or any portion of it. | ||
| 458 | |||
| 459 | 11. Patents. | ||
| 460 | |||
| 461 | A "contributor" is a copyright holder who authorizes use under this | ||
| 462 | License of the Program or a work on which the Program is based. The | ||
| 463 | work thus licensed is called the contributor's "contributor version". | ||
| 464 | |||
| 465 | A contributor's "essential patent claims" are all patent claims | ||
| 466 | owned or controlled by the contributor, whether already acquired or | ||
| 467 | hereafter acquired, that would be infringed by some manner, permitted | ||
| 468 | by this License, of making, using, or selling its contributor version, | ||
| 469 | but do not include claims that would be infringed only as a | ||
| 470 | consequence of further modification of the contributor version. For | ||
| 471 | purposes of this definition, "control" includes the right to grant | ||
| 472 | patent sublicenses in a manner consistent with the requirements of | ||
| 473 | this License. | ||
| 474 | |||
| 475 | Each contributor grants you a non-exclusive, worldwide, royalty-free | ||
| 476 | patent license under the contributor's essential patent claims, to | ||
| 477 | make, use, sell, offer for sale, import and otherwise run, modify and | ||
| 478 | propagate the contents of its contributor version. | ||
| 479 | |||
| 480 | In the following three paragraphs, a "patent license" is any express | ||
| 481 | agreement or commitment, however denominated, not to enforce a patent | ||
| 482 | (such as an express permission to practice a patent or covenant not to | ||
| 483 | sue for patent infringement). To "grant" such a patent license to a | ||
| 484 | party means to make such an agreement or commitment not to enforce a | ||
| 485 | patent against the party. | ||
| 486 | |||
| 487 | If you convey a covered work, knowingly relying on a patent license, | ||
| 488 | and the Corresponding Source of the work is not available for anyone | ||
| 489 | to copy, free of charge and under the terms of this License, through a | ||
| 490 | publicly available network server or other readily accessible means, | ||
| 491 | then you must either (1) cause the Corresponding Source to be so | ||
| 492 | available, or (2) arrange to deprive yourself of the benefit of the | ||
| 493 | patent license for this particular work, or (3) arrange, in a manner | ||
| 494 | consistent with the requirements of this License, to extend the patent | ||
| 495 | license to downstream recipients. "Knowingly relying" means you have | ||
| 496 | actual knowledge that, but for the patent license, your conveying the | ||
| 497 | covered work in a country, or your recipient's use of the covered work | ||
| 498 | in a country, would infringe one or more identifiable patents in that | ||
| 499 | country that you have reason to believe are valid. | ||
| 500 | |||
| 501 | If, pursuant to or in connection with a single transaction or | ||
| 502 | arrangement, you convey, or propagate by procuring conveyance of, a | ||
| 503 | covered work, and grant a patent license to some of the parties | ||
| 504 | receiving the covered work authorizing them to use, propagate, modify | ||
| 505 | or convey a specific copy of the covered work, then the patent license | ||
| 506 | you grant is automatically extended to all recipients of the covered | ||
| 507 | work and works based on it. | ||
| 508 | |||
| 509 | A patent license is "discriminatory" if it does not include within | ||
| 510 | the scope of its coverage, prohibits the exercise of, or is | ||
| 511 | conditioned on the non-exercise of one or more of the rights that are | ||
| 512 | specifically granted under this License. You may not convey a covered | ||
| 513 | work if you are a party to an arrangement with a third party that is | ||
| 514 | in the business of distributing software, under which you make payment | ||
| 515 | to the third party based on the extent of your activity of conveying | ||
| 516 | the work, and under which the third party grants, to any of the | ||
| 517 | parties who would receive the covered work from you, a discriminatory | ||
| 518 | patent license (a) in connection with copies of the covered work | ||
| 519 | conveyed by you (or copies made from those copies), or (b) primarily | ||
| 520 | for and in connection with specific products or compilations that | ||
| 521 | contain the covered work, unless you entered into that arrangement, | ||
| 522 | or that patent license was granted, prior to 28 March 2007. | ||
| 523 | |||
| 524 | Nothing in this License shall be construed as excluding or limiting | ||
| 525 | any implied license or other defenses to infringement that may | ||
| 526 | otherwise be available to you under applicable patent law. | ||
| 527 | |||
| 528 | 12. No Surrender of Others' Freedom. | ||
| 529 | |||
| 530 | If conditions are imposed on you (whether by court order, agreement or | ||
| 531 | otherwise) that contradict the conditions of this License, they do not | ||
| 532 | excuse you from the conditions of this License. If you cannot convey a | ||
| 533 | covered work so as to satisfy simultaneously your obligations under this | ||
| 534 | License and any other pertinent obligations, then as a consequence you may | ||
| 535 | not convey it at all. For example, if you agree to terms that obligate you | ||
| 536 | to collect a royalty for further conveying from those to whom you convey | ||
| 537 | the Program, the only way you could satisfy both those terms and this | ||
| 538 | License would be to refrain entirely from conveying the Program. | ||
| 539 | |||
| 540 | 13. Remote Network Interaction; Use with the GNU General Public License. | ||
| 541 | |||
| 542 | Notwithstanding any other provision of this License, if you modify the | ||
| 543 | Program, your modified version must prominently offer all users | ||
| 544 | interacting with it remotely through a computer network (if your version | ||
| 545 | supports such interaction) an opportunity to receive the Corresponding | ||
| 546 | Source of your version by providing access to the Corresponding Source | ||
| 547 | from a network server at no charge, through some standard or customary | ||
| 548 | means of facilitating copying of software. This Corresponding Source | ||
| 549 | shall include the Corresponding Source for any work covered by version 3 | ||
| 550 | of the GNU General Public License that is incorporated pursuant to the | ||
| 551 | following paragraph. | ||
| 552 | |||
| 553 | Notwithstanding any other provision of this License, you have | ||
| 554 | permission to link or combine any covered work with a work licensed | ||
| 555 | under version 3 of the GNU General Public License into a single | ||
| 556 | combined work, and to convey the resulting work. The terms of this | ||
| 557 | License will continue to apply to the part which is the covered work, | ||
| 558 | but the work with which it is combined will remain governed by version | ||
| 559 | 3 of the GNU General Public License. | ||
| 560 | |||
| 561 | 14. Revised Versions of this License. | ||
| 562 | |||
| 563 | The Free Software Foundation may publish revised and/or new versions of | ||
| 564 | the GNU Affero General Public License from time to time. Such new versions | ||
| 565 | will be similar in spirit to the present version, but may differ in detail to | ||
| 566 | address new problems or concerns. | ||
| 567 | |||
| 568 | Each version is given a distinguishing version number. If the | ||
| 569 | Program specifies that a certain numbered version of the GNU Affero General | ||
| 570 | Public License "or any later version" applies to it, you have the | ||
| 571 | option of following the terms and conditions either of that numbered | ||
| 572 | version or of any later version published by the Free Software | ||
| 573 | Foundation. If the Program does not specify a version number of the | ||
| 574 | GNU Affero General Public License, you may choose any version ever published | ||
| 575 | by the Free Software Foundation. | ||
| 576 | |||
| 577 | If the Program specifies that a proxy can decide which future | ||
| 578 | versions of the GNU Affero General Public License can be used, that proxy's | ||
| 579 | public statement of acceptance of a version permanently authorizes you | ||
| 580 | to choose that version for the Program. | ||
| 581 | |||
| 582 | Later license versions may give you additional or different | ||
| 583 | permissions. However, no additional obligations are imposed on any | ||
| 584 | author or copyright holder as a result of your choosing to follow a | ||
| 585 | later version. | ||
| 586 | |||
| 587 | 15. Disclaimer of Warranty. | ||
| 588 | |||
| 589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY | ||
| 590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT | ||
| 591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY | ||
| 592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, | ||
| 593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||
| 594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM | ||
| 595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF | ||
| 596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. | ||
| 597 | |||
| 598 | 16. Limitation of Liability. | ||
| 599 | |||
| 600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | ||
| 601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS | ||
| 602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY | ||
| 603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE | ||
| 604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF | ||
| 605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD | ||
| 606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), | ||
| 607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF | ||
| 608 | SUCH DAMAGES. | ||
| 609 | |||
| 610 | 17. Interpretation of Sections 15 and 16. | ||
| 611 | |||
| 612 | If the disclaimer of warranty and limitation of liability provided | ||
| 613 | above cannot be given local legal effect according to their terms, | ||
| 614 | reviewing courts shall apply local law that most closely approximates | ||
| 615 | an absolute waiver of all civil liability in connection with the | ||
| 616 | Program, unless a warranty or assumption of liability accompanies a | ||
| 617 | copy of the Program in return for a fee. | ||
| 618 | |||
| 619 | END OF TERMS AND CONDITIONS | ||
| 620 | |||
| 621 | How to Apply These Terms to Your New Programs | ||
| 622 | |||
| 623 | If you develop a new program, and you want it to be of the greatest | ||
| 624 | possible use to the public, the best way to achieve this is to make it | ||
| 625 | free software which everyone can redistribute and change under these terms. | ||
| 626 | |||
| 627 | To do so, attach the following notices to the program. It is safest | ||
| 628 | to attach them to the start of each source file to most effectively | ||
| 629 | state the exclusion of warranty; and each file should have at least | ||
| 630 | the "copyright" line and a pointer to where the full notice is found. | ||
| 631 | |||
| 632 | <one line to give the program's name and a brief idea of what it does.> | ||
| 633 | Copyright (C) <year> <name of author> | ||
| 634 | |||
| 635 | This program is free software: you can redistribute it and/or modify | ||
| 636 | it under the terms of the GNU Affero General Public License as published by | ||
| 637 | the Free Software Foundation, either version 3 of the License, or | ||
| 638 | (at your option) any later version. | ||
| 639 | |||
| 640 | This program is distributed in the hope that it will be useful, | ||
| 641 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 643 | GNU Affero General Public License for more details. | ||
| 644 | |||
| 645 | You should have received a copy of the GNU Affero General Public License | ||
| 646 | along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
| 647 | |||
| 648 | Also add information on how to contact you by electronic and paper mail. | ||
| 649 | |||
| 650 | If your software can interact with users remotely through a computer | ||
| 651 | network, you should also make sure that it provides a way for users to | ||
| 652 | get its source. For example, if your program is a web application, its | ||
| 653 | interface could display a "Source" link that leads users to an archive | ||
| 654 | of the code. There are many ways you could offer source, and different | ||
| 655 | solutions will be better for different programs; see section 13 for the | ||
| 656 | specific requirements. | ||
| 657 | |||
| 658 | You should also get your employer (if you work as a programmer) or school, | ||
| 659 | if any, to sign a "copyright disclaimer" for the program, if necessary. | ||
| 660 | For more information on this, and how to apply and follow the GNU AGPL, see | ||
| 661 | <https://www.gnu.org/licenses/>. | ||
diff --git a/static/bsd_license.txt b/static/bsd_license.txt deleted file mode 100644 index ebc7cdc..0000000 --- a/static/bsd_license.txt +++ /dev/null | |||
| @@ -1,24 +0,0 @@ | |||
| 1 | BSD 2-Clause License | ||
| 2 | |||
| 3 | Copyright (c) 2024, Vineet Kumar | ||
| 4 | |||
| 5 | Redistribution and use in source and binary forms, with or without | ||
| 6 | modification, are permitted provided that the following conditions are met: | ||
| 7 | |||
| 8 | 1. Redistributions of source code must retain the above copyright notice, this | ||
| 9 | list of conditions and the following disclaimer. | ||
| 10 | |||
| 11 | 2. Redistributions in binary form must reproduce the above copyright notice, | ||
| 12 | this list of conditions and the following disclaimer in the documentation | ||
| 13 | and/or other materials provided with the distribution. | ||
| 14 | |||
| 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
| 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
| 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
| 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||
| 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
| 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
| 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
| 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||
| 23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
diff --git a/static/cc-by-4.0.txt b/static/cc-by-nc-sa-4.0.txt index 4ea99c2..7cdbe0b 100644 --- a/static/cc-by-4.0.txt +++ b/static/cc-by-nc-sa-4.0.txt | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | Attribution 4.0 International | 1 | Attribution-NonCommercial-ShareAlike 4.0 International |
| 2 | 2 | ||
| 3 | ======================================================================= | 3 | ======================================================================= |
| 4 | 4 | ||
| @@ -54,16 +54,18 @@ exhaustive, and do not form part of our licenses. | |||
| 54 | 54 | ||
| 55 | ======================================================================= | 55 | ======================================================================= |
| 56 | 56 | ||
| 57 | Creative Commons Attribution 4.0 International Public License | 57 | Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International |
| 58 | Public License | ||
| 58 | 59 | ||
| 59 | By exercising the Licensed Rights (defined below), You accept and agree | 60 | By exercising the Licensed Rights (defined below), You accept and agree |
| 60 | to be bound by the terms and conditions of this Creative Commons | 61 | to be bound by the terms and conditions of this Creative Commons |
| 61 | Attribution 4.0 International Public License ("Public License"). To the | 62 | Attribution-NonCommercial-ShareAlike 4.0 International Public License |
| 62 | extent this Public License may be interpreted as a contract, You are | 63 | ("Public License"). To the extent this Public License may be |
| 63 | granted the Licensed Rights in consideration of Your acceptance of | 64 | interpreted as a contract, You are granted the Licensed Rights in |
| 64 | these terms and conditions, and the Licensor grants You such rights in | 65 | consideration of Your acceptance of these terms and conditions, and the |
| 65 | consideration of benefits the Licensor receives from making the | 66 | Licensor grants You such rights in consideration of benefits the |
| 66 | Licensed Material available under these terms and conditions. | 67 | Licensor receives from making the Licensed Material available under |
| 68 | these terms and conditions. | ||
| 67 | 69 | ||
| 68 | 70 | ||
| 69 | Section 1 -- Definitions. | 71 | Section 1 -- Definitions. |
| @@ -82,7 +84,11 @@ Section 1 -- Definitions. | |||
| 82 | and Similar Rights in Your contributions to Adapted Material in | 84 | and Similar Rights in Your contributions to Adapted Material in |
| 83 | accordance with the terms and conditions of this Public License. | 85 | accordance with the terms and conditions of this Public License. |
| 84 | 86 | ||
| 85 | c. Copyright and Similar Rights means copyright and/or similar rights | 87 | c. BY-NC-SA Compatible License means a license listed at |
| 88 | creativecommons.org/compatiblelicenses, approved by Creative | ||
| 89 | Commons as essentially the equivalent of this Public License. | ||
| 90 | |||
| 91 | d. Copyright and Similar Rights means copyright and/or similar rights | ||
| 86 | closely related to copyright including, without limitation, | 92 | closely related to copyright including, without limitation, |
| 87 | performance, broadcast, sound recording, and Sui Generis Database | 93 | performance, broadcast, sound recording, and Sui Generis Database |
| 88 | Rights, without regard to how the rights are labeled or | 94 | Rights, without regard to how the rights are labeled or |
| @@ -90,29 +96,41 @@ Section 1 -- Definitions. | |||
| 90 | specified in Section 2(b)(1)-(2) are not Copyright and Similar | 96 | specified in Section 2(b)(1)-(2) are not Copyright and Similar |
| 91 | Rights. | 97 | Rights. |
| 92 | 98 | ||
| 93 | d. Effective Technological Measures means those measures that, in the | 99 | e. Effective Technological Measures means those measures that, in the |
| 94 | absence of proper authority, may not be circumvented under laws | 100 | absence of proper authority, may not be circumvented under laws |
| 95 | fulfilling obligations under Article 11 of the WIPO Copyright | 101 | fulfilling obligations under Article 11 of the WIPO Copyright |
| 96 | Treaty adopted on December 20, 1996, and/or similar international | 102 | Treaty adopted on December 20, 1996, and/or similar international |
| 97 | agreements. | 103 | agreements. |
| 98 | 104 | ||
| 99 | e. Exceptions and Limitations means fair use, fair dealing, and/or | 105 | f. Exceptions and Limitations means fair use, fair dealing, and/or |
| 100 | any other exception or limitation to Copyright and Similar Rights | 106 | any other exception or limitation to Copyright and Similar Rights |
| 101 | that applies to Your use of the Licensed Material. | 107 | that applies to Your use of the Licensed Material. |
| 102 | 108 | ||
| 103 | f. Licensed Material means the artistic or literary work, database, | 109 | g. License Elements means the license attributes listed in the name |
| 110 | of a Creative Commons Public License. The License Elements of this | ||
| 111 | Public License are Attribution, NonCommercial, and ShareAlike. | ||
| 112 | |||
| 113 | h. Licensed Material means the artistic or literary work, database, | ||
| 104 | or other material to which the Licensor applied this Public | 114 | or other material to which the Licensor applied this Public |
| 105 | License. | 115 | License. |
| 106 | 116 | ||
| 107 | g. Licensed Rights means the rights granted to You subject to the | 117 | i. Licensed Rights means the rights granted to You subject to the |
| 108 | terms and conditions of this Public License, which are limited to | 118 | terms and conditions of this Public License, which are limited to |
| 109 | all Copyright and Similar Rights that apply to Your use of the | 119 | all Copyright and Similar Rights that apply to Your use of the |
| 110 | Licensed Material and that the Licensor has authority to license. | 120 | Licensed Material and that the Licensor has authority to license. |
| 111 | 121 | ||
| 112 | h. Licensor means the individual(s) or entity(ies) granting rights | 122 | j. Licensor means the individual(s) or entity(ies) granting rights |
| 113 | under this Public License. | 123 | under this Public License. |
| 114 | 124 | ||
| 115 | i. Share means to provide material to the public by any means or | 125 | k. NonCommercial means not primarily intended for or directed towards |
| 126 | commercial advantage or monetary compensation. For purposes of | ||
| 127 | this Public License, the exchange of the Licensed Material for | ||
| 128 | other material subject to Copyright and Similar Rights by digital | ||
| 129 | file-sharing or similar means is NonCommercial provided there is | ||
| 130 | no payment of monetary compensation in connection with the | ||
| 131 | exchange. | ||
| 132 | |||
| 133 | l. Share means to provide material to the public by any means or | ||
| 116 | process that requires permission under the Licensed Rights, such | 134 | process that requires permission under the Licensed Rights, such |
| 117 | as reproduction, public display, public performance, distribution, | 135 | as reproduction, public display, public performance, distribution, |
| 118 | dissemination, communication, or importation, and to make material | 136 | dissemination, communication, or importation, and to make material |
| @@ -120,13 +138,13 @@ Section 1 -- Definitions. | |||
| 120 | public may access the material from a place and at a time | 138 | public may access the material from a place and at a time |
| 121 | individually chosen by them. | 139 | individually chosen by them. |
| 122 | 140 | ||
| 123 | j. Sui Generis Database Rights means rights other than copyright | 141 | m. Sui Generis Database Rights means rights other than copyright |
| 124 | resulting from Directive 96/9/EC of the European Parliament and of | 142 | resulting from Directive 96/9/EC of the European Parliament and of |
| 125 | the Council of 11 March 1996 on the legal protection of databases, | 143 | the Council of 11 March 1996 on the legal protection of databases, |
| 126 | as amended and/or succeeded, as well as other essentially | 144 | as amended and/or succeeded, as well as other essentially |
| 127 | equivalent rights anywhere in the world. | 145 | equivalent rights anywhere in the world. |
| 128 | 146 | ||
| 129 | k. You means the individual or entity exercising the Licensed Rights | 147 | n. You means the individual or entity exercising the Licensed Rights |
| 130 | under this Public License. Your has a corresponding meaning. | 148 | under this Public License. Your has a corresponding meaning. |
| 131 | 149 | ||
| 132 | 150 | ||
| @@ -140,9 +158,10 @@ Section 2 -- Scope. | |||
| 140 | exercise the Licensed Rights in the Licensed Material to: | 158 | exercise the Licensed Rights in the Licensed Material to: |
| 141 | 159 | ||
| 142 | a. reproduce and Share the Licensed Material, in whole or | 160 | a. reproduce and Share the Licensed Material, in whole or |
| 143 | in part; and | 161 | in part, for NonCommercial purposes only; and |
| 144 | 162 | ||
| 145 | b. produce, reproduce, and Share Adapted Material. | 163 | b. produce, reproduce, and Share Adapted Material for |
| 164 | NonCommercial purposes only. | ||
| 146 | 165 | ||
| 147 | 2. Exceptions and Limitations. For the avoidance of doubt, where | 166 | 2. Exceptions and Limitations. For the avoidance of doubt, where |
| 148 | Exceptions and Limitations apply to Your use, this Public | 167 | Exceptions and Limitations apply to Your use, this Public |
| @@ -172,7 +191,13 @@ Section 2 -- Scope. | |||
| 172 | Licensed Rights under the terms and conditions of this | 191 | Licensed Rights under the terms and conditions of this |
| 173 | Public License. | 192 | Public License. |
| 174 | 193 | ||
| 175 | b. No downstream restrictions. You may not offer or impose | 194 | b. Additional offer from the Licensor -- Adapted Material. |
| 195 | Every recipient of Adapted Material from You | ||
| 196 | automatically receives an offer from the Licensor to | ||
| 197 | exercise the Licensed Rights in the Adapted Material | ||
| 198 | under the conditions of the Adapter's License You apply. | ||
| 199 | |||
| 200 | c. No downstream restrictions. You may not offer or impose | ||
| 176 | any additional or different terms or conditions on, or | 201 | any additional or different terms or conditions on, or |
| 177 | apply any Effective Technological Measures to, the | 202 | apply any Effective Technological Measures to, the |
| 178 | Licensed Material if doing so restricts exercise of the | 203 | Licensed Material if doing so restricts exercise of the |
| @@ -204,7 +229,9 @@ Section 2 -- Scope. | |||
| 204 | Rights, whether directly or through a collecting society | 229 | Rights, whether directly or through a collecting society |
| 205 | under any voluntary or waivable statutory or compulsory | 230 | under any voluntary or waivable statutory or compulsory |
| 206 | licensing scheme. In all other cases the Licensor expressly | 231 | licensing scheme. In all other cases the Licensor expressly |
| 207 | reserves any right to collect such royalties. | 232 | reserves any right to collect such royalties, including when |
| 233 | the Licensed Material is used other than for NonCommercial | ||
| 234 | purposes. | ||
| 208 | 235 | ||
| 209 | 236 | ||
| 210 | Section 3 -- License Conditions. | 237 | Section 3 -- License Conditions. |
| @@ -249,14 +276,28 @@ following conditions. | |||
| 249 | reasonable to satisfy the conditions by providing a URI or | 276 | reasonable to satisfy the conditions by providing a URI or |
| 250 | hyperlink to a resource that includes the required | 277 | hyperlink to a resource that includes the required |
| 251 | information. | 278 | information. |
| 252 | |||
| 253 | 3. If requested by the Licensor, You must remove any of the | 279 | 3. If requested by the Licensor, You must remove any of the |
| 254 | information required by Section 3(a)(1)(A) to the extent | 280 | information required by Section 3(a)(1)(A) to the extent |
| 255 | reasonably practicable. | 281 | reasonably practicable. |
| 256 | 282 | ||
| 257 | 4. If You Share Adapted Material You produce, the Adapter's | 283 | b. ShareAlike. |
| 258 | License You apply must not prevent recipients of the Adapted | 284 | |
| 259 | Material from complying with this Public License. | 285 | In addition to the conditions in Section 3(a), if You Share |
| 286 | Adapted Material You produce, the following conditions also apply. | ||
| 287 | |||
| 288 | 1. The Adapter's License You apply must be a Creative Commons | ||
| 289 | license with the same License Elements, this version or | ||
| 290 | later, or a BY-NC-SA Compatible License. | ||
| 291 | |||
| 292 | 2. You must include the text of, or the URI or hyperlink to, the | ||
| 293 | Adapter's License You apply. You may satisfy this condition | ||
| 294 | in any reasonable manner based on the medium, means, and | ||
| 295 | context in which You Share Adapted Material. | ||
| 296 | |||
| 297 | 3. You may not offer or impose any additional or different terms | ||
| 298 | or conditions on, or apply any Effective Technological | ||
| 299 | Measures to, Adapted Material that restrict exercise of the | ||
| 300 | rights granted under the Adapter's License You apply. | ||
| 260 | 301 | ||
| 261 | 302 | ||
| 262 | Section 4 -- Sui Generis Database Rights. | 303 | Section 4 -- Sui Generis Database Rights. |
| @@ -266,12 +307,14 @@ apply to Your use of the Licensed Material: | |||
| 266 | 307 | ||
| 267 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right | 308 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right |
| 268 | to extract, reuse, reproduce, and Share all or a substantial | 309 | to extract, reuse, reproduce, and Share all or a substantial |
| 269 | portion of the contents of the database; | 310 | portion of the contents of the database for NonCommercial purposes |
| 311 | only; | ||
| 270 | 312 | ||
| 271 | b. if You include all or a substantial portion of the database | 313 | b. if You include all or a substantial portion of the database |
| 272 | contents in a database in which You have Sui Generis Database | 314 | contents in a database in which You have Sui Generis Database |
| 273 | Rights, then the database in which You have Sui Generis Database | 315 | Rights, then the database in which You have Sui Generis Database |
| 274 | Rights (but not its individual contents) is Adapted Material; and | 316 | Rights (but not its individual contents) is Adapted Material, |
| 317 | including for purposes of Section 3(b); and | ||
| 275 | 318 | ||
| 276 | c. You must comply with the conditions in Section 3(a) if You Share | 319 | c. You must comply with the conditions in Section 3(a) if You Share |
| 277 | all or a substantial portion of the contents of the database. | 320 | all or a substantial portion of the contents of the database. |
| @@ -372,7 +415,6 @@ Section 8 -- Interpretation. | |||
| 372 | that apply to the Licensor or You, including from the legal | 415 | that apply to the Licensor or You, including from the legal |
| 373 | processes of any jurisdiction or authority. | 416 | processes of any jurisdiction or authority. |
| 374 | 417 | ||
| 375 | |||
| 376 | ======================================================================= | 418 | ======================================================================= |
| 377 | 419 | ||
| 378 | Creative Commons is not a party to its public | 420 | Creative Commons is not a party to its public |
| @@ -393,3 +435,4 @@ the avoidance of doubt, this paragraph does not form part of the | |||
| 393 | public licenses. | 435 | public licenses. |
| 394 | 436 | ||
| 395 | Creative Commons may be contacted at creativecommons.org. | 437 | Creative Commons may be contacted at creativecommons.org. |
| 438 | |||
diff --git a/static/main.css b/static/main.css new file mode 100644 index 0000000..ef28c74 --- /dev/null +++ b/static/main.css | |||
| @@ -0,0 +1,203 @@ | |||
| 1 | /* fonts */ | ||
| 2 | @font-face { | ||
| 3 | font-family: "Comic Mono"; | ||
| 4 | font-weight: normal; | ||
| 5 | font-style: normal; | ||
| 6 | font-display: swap; | ||
| 7 | src: url('https://dtinth.github.io/comic-mono-font/ComicMono.ttf'); | ||
| 8 | } | ||
| 9 | |||
| 10 | @font-face { | ||
| 11 | font-family: "Comic Mono"; | ||
| 12 | font-weight: bold; | ||
| 13 | font-style: normal; | ||
| 14 | font-display: swap; | ||
| 15 | src: url('https://dtinth.github.io/comic-mono-font/ComicMono-Bold.ttf'); | ||
| 16 | } | ||
| 17 | |||
| 18 | @font-face { | ||
| 19 | font-family: 'Comic Neue'; | ||
| 20 | src: local('Comic Neue Italic'), local('ComicNeue-Italic'), | ||
| 21 | url('https://github.com/crozynski/comicneue/raw/refs/heads/master/Fonts/WebFonts/ComicNeue-Italic.woff2') format('woff2'); | ||
| 22 | font-weight: normal; | ||
| 23 | font-style: italic; | ||
| 24 | font-display: swap; | ||
| 25 | } | ||
| 26 | |||
| 27 | @font-face { | ||
| 28 | font-family: 'Comic Neue'; | ||
| 29 | src: local('Comic Neue Bold'), local('ComicNeue-Bold'), | ||
| 30 | url('https://github.com/crozynski/comicneue/raw/refs/heads/master/Fonts/WebFonts/ComicNeue-Bold.woff2') format('woff2'); | ||
| 31 | font-weight: bold; | ||
| 32 | font-style: normal; | ||
| 33 | font-display: swap; | ||
| 34 | } | ||
| 35 | |||
| 36 | @font-face { | ||
| 37 | font-family: 'Comic Neue'; | ||
| 38 | src: local('Comic Neue Bold Italic'), local('ComicNeue-BoldItalic'), | ||
| 39 | url('https://github.com/crozynski/comicneue/raw/refs/heads/master/Fonts/WebFonts/ComicNeue-BoldItalic.woff2') format('woff2'); | ||
| 40 | font-weight: bold; | ||
| 41 | font-style: italic; | ||
| 42 | font-display: swap; | ||
| 43 | } | ||
| 44 | |||
| 45 | @font-face { | ||
| 46 | font-family: 'Comic Neue'; | ||
| 47 | src: local('Comic Neue Regular'), local('ComicNeue-Regular'), | ||
| 48 | url('https://github.com/crozynski/comicneue/raw/refs/heads/master/Fonts/WebFonts/ComicNeue-Regular.woff2') format('woff2'); | ||
| 49 | font-weight: normal; | ||
| 50 | font-style: normal; | ||
| 51 | font-display: swap; | ||
| 52 | } | ||
| 53 | |||
| 54 | /* main */ | ||
| 55 | |||
| 56 | :root { | ||
| 57 | /* kaolin valley light */ | ||
| 58 | --background: #faf2e9; | ||
| 59 | --brbackground: #ebd7be; | ||
| 60 | --foreground: #5e5854; | ||
| 61 | --brforeground: #6b6560; | ||
| 62 | --border: #f0dfca; | ||
| 63 | |||
| 64 | --black: #5e5854; | ||
| 65 | --brblack: #544b44; | ||
| 66 | --red: #d42215; | ||
| 67 | --green: #0d7a75; | ||
| 68 | --yellow: #d1832e; | ||
| 69 | --blue: #526af3; | ||
| 70 | --magenta: #cf44ac; | ||
| 71 | --cyan: #0bc9cf; | ||
| 72 | --white: #ebd7be; | ||
| 73 | } | ||
| 74 | |||
| 75 | @media (prefers-color-scheme: dark) { | ||
| 76 | :root { | ||
| 77 | /* kaolin valley dark */ | ||
| 78 | --background: #1c1616; | ||
| 79 | --brbackground: #5e5854; | ||
| 80 | --foreground: #eee6d3; | ||
| 81 | --brforeground: #c7c2af; | ||
| 82 | --border: #2e2a29; | ||
| 83 | |||
| 84 | --black: #28211e; | ||
| 85 | --brblack: #544b44; | ||
| 86 | --red: #e84c58; | ||
| 87 | --green: #91f368; | ||
| 88 | --yellow: #eed891; | ||
| 89 | --blue: #41b0f3; | ||
| 90 | --magenta: #cea2ca; | ||
| 91 | --cyan: #6bd9db; | ||
| 92 | --white: #eee6d3; | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | html { | ||
| 97 | color: var(--foreground); | ||
| 98 | background-color: var(--background); | ||
| 99 | } | ||
| 100 | |||
| 101 | nav { | ||
| 102 | display: flex; | ||
| 103 | justify-content: space-between; | ||
| 104 | align-items: center; | ||
| 105 | margin-bottom: 1rem; | ||
| 106 | } | ||
| 107 | |||
| 108 | nav ul { | ||
| 109 | display: flex; | ||
| 110 | list-style: none; | ||
| 111 | margin: 0; | ||
| 112 | padding: 0; | ||
| 113 | gap: 1rem; | ||
| 114 | } | ||
| 115 | |||
| 116 | body { | ||
| 117 | max-width: 720px; | ||
| 118 | margin: 0 auto; | ||
| 119 | padding: 1rem; | ||
| 120 | font-family: "Comic Neue", "Comic Sans MS", sans-serif; | ||
| 121 | } | ||
| 122 | |||
| 123 | h2 { | ||
| 124 | margin-bottom: 0; | ||
| 125 | } | ||
| 126 | |||
| 127 | a { | ||
| 128 | color: var(--yellow); | ||
| 129 | text-decoration: none; | ||
| 130 | } | ||
| 131 | |||
| 132 | a:hover { | ||
| 133 | text-decoration: underline; | ||
| 134 | } | ||
| 135 | |||
| 136 | a:visited { | ||
| 137 | color: var(--green); | ||
| 138 | } | ||
| 139 | |||
| 140 | article { | ||
| 141 | margin: 0 auto; | ||
| 142 | line-height: 1.3; | ||
| 143 | } | ||
| 144 | |||
| 145 | article img { | ||
| 146 | display: block !important; | ||
| 147 | margin: 0 auto !important; | ||
| 148 | max-width: 90%; | ||
| 149 | } | ||
| 150 | |||
| 151 | @media (max-width: 640px) { | ||
| 152 | article img { | ||
| 153 | max-width: calc(100% - 2rem); | ||
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 157 | footer { | ||
| 158 | margin-top: 2rem; | ||
| 159 | text-align: center; | ||
| 160 | font-size: 0.8rem; | ||
| 161 | color: var(--brblack); | ||
| 162 | } | ||
| 163 | |||
| 164 | pre { | ||
| 165 | background-color: var(--brbackground); | ||
| 166 | padding: 0.25rem 1rem; | ||
| 167 | margin: 0 -1rem; | ||
| 168 | max-width: 100%; | ||
| 169 | overflow-x: auto; | ||
| 170 | } | ||
| 171 | |||
| 172 | pre, code { | ||
| 173 | font-family: "Comic Code", "Comic Mono", monospace; | ||
| 174 | } | ||
| 175 | |||
| 176 | summary { | ||
| 177 | cursor: pointer; | ||
| 178 | background-color: var(--brbackground); | ||
| 179 | padding: 0.25rem 1rem; | ||
| 180 | margin: 0 -1rem; | ||
| 181 | } | ||
| 182 | |||
| 183 | details[open] { | ||
| 184 | border-bottom: 1rem solid var(--border); | ||
| 185 | margin: 0 -1rem 1rem; | ||
| 186 | padding: 0 1rem; | ||
| 187 | } | ||
| 188 | |||
| 189 | blockquote { | ||
| 190 | border-left: 5px solid var(--border); | ||
| 191 | background-color: var(--brbackground); | ||
| 192 | padding: 0 1rem; | ||
| 193 | margin-left: calc(-1rem - 5px); | ||
| 194 | margin-right: -1rem; | ||
| 195 | } | ||
| 196 | |||
| 197 | .text-center { | ||
| 198 | text-align: center; | ||
| 199 | } | ||
| 200 | |||
| 201 | .date { | ||
| 202 | font-family: "Comic Code", "Comic Mono", monospace; | ||
| 203 | } | ||
diff --git a/theme.scm b/theme.scm new file mode 100644 index 0000000..4485c62 --- /dev/null +++ b/theme.scm | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | (define-module (theme) | ||
| 2 | #:use-module (haunt artifact) | ||
| 3 | #:use-module (haunt asset) | ||
| 4 | #:use-module (haunt builder blog) | ||
| 5 | #:use-module (haunt html) | ||
| 6 | #:use-module (haunt post) | ||
| 7 | #:use-module (haunt site) | ||
| 8 | #:use-module (srfi srfi-19) | ||
| 9 | #:export (vin-theme)) | ||
| 10 | |||
| 11 | (define (link name uri) | ||
| 12 | `(a (@ (href ,uri)) ,name)) | ||
| 13 | |||
| 14 | (define vin-theme | ||
| 15 | (theme #:name "vin" | ||
| 16 | #:layout | ||
| 17 | (lambda (site title body) | ||
| 18 | `((doctype "html") | ||
| 19 | (head | ||
| 20 | (meta (@ (charset "utf-8"))) | ||
| 21 | (meta (@ (name "viewport") | ||
| 22 | (content "width=device-width, initial-scale=1"))) | ||
| 23 | (title ,(string-append title " - " (site-title site))) | ||
| 24 | (link (@ (rel "alternate") | ||
| 25 | (type "application/atom+xml") | ||
| 26 | (title "Atom feed") | ||
| 27 | (href "/feed.xml"))) | ||
| 28 | (link (@ (rel "icon") | ||
| 29 | (type "image/png") | ||
| 30 | (href "/static/AT_terminus.png"))) | ||
| 31 | (link (@ (rel "stylesheet") | ||
| 32 | (type "text/css") | ||
| 33 | (href "/static/main.css"))) | ||
| 34 | (body | ||
| 35 | (div (@ (class "container")) | ||
| 36 | (nav | ||
| 37 | (ul (li ,(link "Vineet K" "/"))) | ||
| 38 | (ul (li ,(link "About Me" "/about.html")) | ||
| 39 | (li ,(link "Blog" "/index.html")) | ||
| 40 | ;; (li ,(link "Projects" "/projects.html")) | ||
| 41 | )) | ||
| 42 | ,body | ||
| 43 | (footer (@ (class "text-center")) | ||
| 44 | (p "The content for the site is under the " ,(link "CC-BY-NC-SA-4.0 License" "/static/cc-by-nc-sa-4.0.txt") ". " | ||
| 45 | "The code for this site is under the " ,(link "GNU AGPLv3 License" "/static/agpl-3.0.txt") "."))))))) | ||
| 46 | #:post-template | ||
| 47 | (lambda (post) | ||
| 48 | `((article | ||
| 49 | (h1 (@ (class "title")) | ||
| 50 | ,(post-ref post 'title)) | ||
| 51 | (div (@ (class "date")) | ||
| 52 | ,(date->string (post-date post) | ||
| 53 | "~B ~d, ~Y")) | ||
| 54 | (div (@ (class "post")) | ||
| 55 | ,(post-sxml post))))) | ||
| 56 | #:collection-template | ||
| 57 | (lambda (site title posts prefix) | ||
| 58 | (define (post-uri post) | ||
| 59 | (string-append prefix "/" (site-post-slug site post) ".html")) | ||
| 60 | `((h2 ,title " " | ||
| 61 | (a (@ (href "/feed.xml")) "(feed)")) | ||
| 62 | ,(map (lambda (post) | ||
| 63 | (let ((uri (post-uri post))) | ||
| 64 | `(div (@ (class "posts")) | ||
| 65 | (div (@ (class "post")) | ||
| 66 | (span (span (@ (class "date")) | ||
| 67 | ,(date->string | ||
| 68 | (post-date post) | ||
| 69 | "~Y-~m-~d")) | ||
| 70 | " - " | ||
| 71 | (a (@ (href ,uri)) | ||
| 72 | ,(post-ref post 'title))))))) | ||
| 73 | posts))))) | ||
diff --git a/update.sh b/update.sh deleted file mode 100755 index 9853f61..0000000 --- a/update.sh +++ /dev/null | |||
| @@ -1,4 +0,0 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | hugo | ||
| 3 | #rsync --exclude="update.sh" --delete -ash . vineetk.net:/usr/local/www/vineetk_html/ | ||
| 4 | rsync --exclude="update.sh" --delete -ash public/ 10.0.13.1:/var/www/vineetk_html/ | ||
