diff --git a/.travis.yml b/.travis.yml index 2896159..8c03ef9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,20 @@ language: ruby cache: + apt: true bundler: true # Cache nanoc directories directories: - output - tmp +addons: + apt: + packages: + - pandoc + - texlive + - lmodern + branches: only: - master diff --git a/Gemfile b/Gemfile index feb18d3..ca9cbca 100644 --- a/Gemfile +++ b/Gemfile @@ -8,6 +8,7 @@ gem 'coffee-script' gem 'icalendar' # ical files gem 'kramdown' gem 'sass' +gem 'typogruby' # Needed for atom_feed in blogging helper gem 'builder' @@ -19,6 +20,9 @@ gem 'therubyracer' # for reading time gem 'words_counted' +# Compiling reports from .md to .pdf +gem 'pandoc-ruby' + group :development do gem 'adsf' gem 'highline' diff --git a/Gemfile.lock b/Gemfile.lock index db36c53..b5e2cf1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -21,11 +21,11 @@ GEM csspool-st (= 3.1.2) json csspool-st (3.1.2) - ddmemoize (1.0.0a3) - ddtelemetry (= 1.0.0a2) + ddmemoize (1.0.0) + ddmetrics (~> 1.0) ref (~> 2.0) + ddmetrics (1.0.0) ddplugin (1.0.1) - ddtelemetry (1.0.0a2) execjs (2.7.0) ffi (1.9.18) formatador (0.2.5) @@ -66,13 +66,14 @@ GEM css_press multi_js (0.1.0) uglifier (~> 2) - nanoc (4.8.19) + nanoc (4.9.1) addressable (~> 2.5) cri (~> 2.8) - ddmemoize (= 1.0.0a3) + ddmemoize (~> 1.0) + ddmetrics (~> 1.0) ddplugin (~> 1.0) - ddtelemetry (= 1.0.0a2) hamster (~> 3.0) + parallel (~> 1.12) ref (~> 2.0) slow_enumerator_tools (~> 1.0) nenv (0.3.0) @@ -81,16 +82,19 @@ GEM notiffany (0.1.1) nenv (~> 0.1) shellany (~> 0.0) + pandoc-ruby (2.0.2) + parallel (1.12.1) pry (0.11.3) coderay (~> 1.1.0) method_source (~> 0.9.0) - public_suffix (3.0.1) + public_suffix (3.0.2) rack (2.0.3) rb-fsevent (0.10.2) rb-inotify (0.9.10) ffi (>= 0.5.0, < 2) ref (2.0.0) ruby_dep (1.5.0) + rubypants (0.7.0) sass (3.5.5) sass-listen (~> 4.0.0) sass-listen (4.0.0) @@ -104,6 +108,8 @@ GEM libv8 (~> 3.16.14.15) ref thor (0.20.0) + typogruby (1.0.18) + rubypants uglifier (2.7.2) execjs (>= 0.3.0) json (>= 1.8.0) @@ -126,10 +132,12 @@ DEPENDENCIES icalendar kramdown nanoc + pandoc-ruby sass terminal-notifier terminal-notifier-guard therubyracer + typogruby w3c_validators words_counted diff --git a/README.md b/README.md index 285d4a4..39342dd 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,8 @@ bundle install npm install ``` +You will (momentarily) also need `pandoc` and `latex` to compile the reports from the board meetings. Refer to your OS package manager to install these things. + These will pull in all Ruby and Node.js dependencies. If everything goes well, you should be able to execute the following. ```bash diff --git a/Rules b/Rules index 493f8d3..128fede 100644 --- a/Rules +++ b/Rules @@ -23,6 +23,8 @@ preprocess do all_events.each do |event| check_schema(:event, event) end + + add_report_metadata end # @@ -87,6 +89,8 @@ compile '/blog/*/*' do layout '/generic.*' layout '/default.*' filter :erb + + filter :typogruby end compile '/blog/*/*', rep: :text do @@ -103,11 +107,11 @@ end # compile '/projects/*' do filter :kramdown + + # Don't write out the projects themselves for now + write nil end -# Don't create specific project pages for now -route '/projects/*' do; end - compile '/*_search.json' do filter :erb end @@ -116,6 +120,16 @@ compile '/**/*.ics' do filter :erb end +# +# REPORTS +# + +compile '/about/verslagen/*/*.md', rep: :pdf do + filter :pandoc_pdf, args: { f: :markdown } + + write ext: 'pdf' +end + # # GENERIC ERB PAGES # diff --git a/content/about/verslagen.erb b/content/about/verslagen.erb index d1a9b10..c765ea1 100644 --- a/content/about/verslagen.erb +++ b/content/about/verslagen.erb @@ -1,3 +1,9 @@
-

Verslagen

+

Reports

+ <% reports.group_by {|r| r[:academic_year]}.each do |year, y_reports| %> +

<%= year %>

+ <% y_reports.each do |report| %> + Report <%= report[:date].strftime('%d %B %Y') %>
+ <% end %> + <% end %>
diff --git a/content/about/verslagen/17-18/2017-11-20.md b/content/about/verslagen/17-18/2017-11-20.md new file mode 100644 index 0000000..2763a35 --- /dev/null +++ b/content/about/verslagen/17-18/2017-11-20.md @@ -0,0 +1,94 @@ +% Bestuursvergadering 2 +% Isaura Claeys +% Datum: 20/11/2017 - 13:00 + +Status: Gesloten + +# Verslag vorige vergadering +* https://docs.google.com/document/d/1JTZ3PmzZfooRkfUjZCoBqdfzMDKA31XdfpiwaR1qPWE/edit + + +# Financiën +* Afronden subsidies dit jaar + * Deadline 1 december + * 130 euro aan subsidies + * 381 euro op rekening + 600 in de kassa + * Verhoging prijzen drank publieke events (bvb Hashcode) voor niet-leden (afronden naar boven) + * Tab + 1. fixen codenight + overleggen met benji + 2. Mails sturen + * Hydra + 1. Veel te veel geld over + 2. IPad gekocht (voorgeschoten door timo) + 3. T-Shirts +* Terugbetaling Giant Progressbar destro +* Terugbetaling MOZAIC codenight drinks destro + + +# Sysadmin +* Sysadmini’s + * Lorin kuist asana op + voegt nieuwe sysadmini’s toe + + +# Activiteiten +* Lan: Alles in orde? (competities ed.) + * Sigasi contacteren met winnaars + * Jeroen moet stoppen met tam zijn +* Internet freedom + * https://docs.google.com/document/d/1zgM6jF2mmNyfXKi_SHFMZYLywnJvLPDq0sLxAxb9Bps/edit# + * Mensen fixen +* Talk Delaware + * Datum 18/04 + * Verantwoordelijke: Laurens, Wout en elo helpen +* Ricing-avond 04/12 + * Tiles & Terminals 2 + * Ideeën? + 1. Blogpost met links + 2. Korte demo’s met workflow tips + 3. Oproep om mensen te vinden die hun setup willen showen + 4. Felix, Detlev, Ketnet, Rien + * Brainstormavond met Detlev: DOODLE + * Workflow stresstesting + * Contest: om ter snelst typen op een mechanisch toetsenbord +* Feli talk (GDPR) + * Europees dataprotocol + * Via GSR? +* E&F avond + * FP progtalen gebruiken? + * Uitstellen naar 2de semester: 2de week + * Eerstejaars optrommelen + * DOODLE voor brainstorm +* Pannenkoeken en Jenever Codenight-Avond + * HELL YEAH + * 30 november TBD +* Blogposts/Eventposts schrijven voor vastgepinde events! + * Tiles & terminals + * Delaware talk: + 1. Poster + 2. Blogpost +* Vlaamse Programmeerwedstrijd! + * Jonathan + isaura + * Poke andy + +# Projecten updates +* 12Urenloop + * Crew: Ziggy + Jonathan + Tibo +* G2 + * Gamification 2 + * Project en event management tool +* MOZAIC + * 2de grote mozaic-codenight + * React rewrite gaat vooruit + +# Discussiepunten + +# Trivia +* Slotmachien was kapot: Jeroen merkt op dat als ge gewoon regelmatig es moet aanduwen, dan kan hij er niet van vallen. +* Heeft Ilion de sleutel van Stijn? -> Neen. +* Wanneer zeuswpi.org gebruiken? + * Komt bij asana taakjes + * Certificaten aanvragen + +# Vrij moment + +# Todo's diff --git a/content/about/verslagen/17-18/2018-02-12.md b/content/about/verslagen/17-18/2018-02-12.md new file mode 100644 index 0000000..82a93e7 --- /dev/null +++ b/content/about/verslagen/17-18/2018-02-12.md @@ -0,0 +1,103 @@ +% Bestuursvergadering 3 +% Isaura Claeys +% 21/02/2018 - 17:25 + +# Verslag vorige vergadering + Check + +# Financiën +* WVK Subsidies + * Goedgekeurd: +50 euro extra tov AJ 2016-2017 (1100 in totaal) +* Overzicht + * 650 op de bank + * 220 in de kassa + * Hydra: 1029 terugkrijgen voor Hydra + * Stuw moeten we ook terugkrijgen + * 1800 hebben we atm in totaal + * 839 tab schulden atm +* TV + * Mailen als subsidies bij DSA verwerkt zijn +* Partnerships + * Aparte mailinglijst waar leden zich op kunnen uitschrijven als nodig + * Pakketten aanbieden + 1. Evenement (50) + 2. Vacature mailinglijst/site + 3. Logo op poster/site (enkel bij sponsoring event) + 4. Codenights sponsoren + 5. Prijzen sponsoren + 6. 1 pakket met combinatie van alles + * Wie? Timo + * Ocean Garden en Ocean Garden codenight? + * Timo organiseert aparte vergadering hiervoor +* Lorin is een tomaat, want hij heeft voor de eerste keer in 10 jaar 100 meter gefietst. +* Ereleden + * Kandidaten: pietervdv + * Minimum 50 euro: poster + site (optioneel) + * Dino doet dingen + +# Sysadmin +* Deployen MOZAIC + * Met Wout afspreken +* Dingen mogen gebeuren + * Asana + +# Activiteiten +* Hashcode + * Delhaizerun vrijdag + * Extra locatie + * 300 euro aan pizza’s: Lorin en Rien +* VPW + * We zijn ervoorbij + * In orde! + * Bus zit vol! + * Je bent goed bezig! + * Behalve Lorin en zijn potentieel team van Wout zijn lief +* Ceneka Talks + * 18 april + * Delaware komt + * Maar wie weet waar het over gaat + * Camera bij DICT regelen + * Eten regelen avond zelf + * Barmensen regelen +* Lightning talks + * Komt in orde +* 12Urenloop + * Jeroen wordt teamlead IT + * Volgende vrijdag 12UL codenight + * Tent: Feliciaan vragen hoe subsidieren? +* HTTPizza + * Momenteel afgelast + +# Projecten updates + * MOZAIC + * Intel AI ding van maken if need be + * Meer bestuur rond krijgen nu + 1. Organiseren + inplannen + promo + * Inplannen introductie (presentatie etc.) + * Rien gaat helpen! + * Volgende donderdagmiddag: 11.30u + * Hydra + * Dingen gaan vooruit + * Feli gaat traag + * Lekker + * G2 + * Verschil met gamification: stats zijn een bijzaak, doel is participatie verhogen + +# Discussiepunten +* Rien zegt iets: Ik stel voor dat we eventueel toekomstige bestuursleden bij het bestuur beginnen betrekken. + - Niet bij vergaderingen betrekken + +# Trivia +* Cegeka antwoorden + * Timo + die andere partnership mail +* VEK antwoorden + * wout +* Wina Antwoorden + * Infodinges voor de master informatica + * Rien + +# Vrij moment +Ilion doet een bekentenis: Ik lees mijn mails nooit. + + +# Todo's: diff --git a/content/assets/images/mozaic.png b/content/assets/images/mozaic.png new file mode 100644 index 0000000..e453967 Binary files /dev/null and b/content/assets/images/mozaic.png differ diff --git a/content/assets/stylesheets/includes/general.scss b/content/assets/stylesheets/includes/general.scss index ef0d02e..13aed47 100644 --- a/content/assets/stylesheets/includes/general.scss +++ b/content/assets/stylesheets/includes/general.scss @@ -3,6 +3,17 @@ text-align: justify; } +pre .line-numbers { + margin-right: 10px; + margin-left: -10px; +} + +.caps { + text-transform: uppercase; + font-size: 85%; + letter-spacing: 1px; +} + // Override box styling without round corners .box { margin-bottom:10px; diff --git a/content/assets/stylesheets/main.scss b/content/assets/stylesheets/main.scss index 65d6947..6e97591 100644 --- a/content/assets/stylesheets/main.scss +++ b/content/assets/stylesheets/main.scss @@ -9,14 +9,22 @@ flex: none; } +body { + +} + // Sticky footer -body.site { - overflow-x: hidden; +body { + hyphens: auto; - display: flex; - min-height: 100vh; - flex-direction: column; + &.site { + overflow-x: hidden; + + display: flex; + min-height: 100vh; + flex-direction: column; + } .wrapper { flex: 1; diff --git a/content/blog/17-18/cscbe.md b/content/blog/17-18/cscbe.md new file mode 100644 index 0000000..b8e73be --- /dev/null +++ b/content/blog/17-18/cscbe.md @@ -0,0 +1,96 @@ +--- +author: David Vandorpe +title: 'Cyber Security Challenge 2018: Radium' +created_at: 08/03/2018 +toc: true +--- + +**Category:** Network Security +**Points:** 150 + +**Description:** + +Someone implemented a protocol to execute (privileged) commands on a server. After months of analysis, our word-class TAO team didn't find a single buffer overflow.. However, they were able to compromise a router between a communicating client and server. + +To perform a man-in-the-middle attack through this router, forward data between 52.210.242.66:8023 (this represents the server) and 52.210.242.66:8024 (this represents the client). + +See client.c for an example command to do this. Abuse the resulting man-in-the-middle position to somehow obtain the ability to execute privileged commands! + +*Hint*: When is the authenticity of a packet verified? When is the data payload of a packet decrypted? + +[Source code](https://zeus.ugent.be/zeuswpi/jaWQQLqU.zip) + +## Introduction + +This challenge proved to be possibly the hardest challenge, going unsolved until the organisers decided to reveal a hint near the end of the competition. Even then, our team was the only one to solve it. + +## Write-up + +The zip file contains the code ran on the server and the client. The client and server share a secret password and a secret key. The flow to request the flag is as follow: + +* Client sends the randomly generated client nonce to the server +* Server replies with a randomly generated server nonce. + - The session key (all following communications will use this key) is now `HMAC_SHA256(secret_key, "CSCBE18 Session Key Generation" || client_nonce || server_nonce)` +* The client sends a flag request to the server, which requires a password. Unfortunately this password is encrypted. +* The server responds with the (encrypted) flag + +The same routine was also available without encryption if the client didn't pass a NONCE in it's handshake. + +So, how do we get our flag? Let's list some ideas: + +* Find an attack on the encryption algorithm (AES in OFB mode) +* Try to trick client and server to use the flow without encryption +* Try to set the key to a known value +* Try to trick the server into dumping the flag without a password +* Try to trick the server into using a known encryption key +* Try to generate an error message on the server that includes (a part of) the flag or encryption key +* Try to generate an error message on the client that includes (a part of) the flag or encryption key + +Let's see what these ideas lead to. + +We found a [writeup](https://shrikantadhikarla.wordpress.com/2016/03/08/des-ofb-writeup-boston-key-party-ctf/) from another CTF that cracks DES encryption in OFB mode. The key weakness here is using a weak DES key (guaranteeing `x == DES(DES(x))`), in combination with OFB. But wait a second, the program uses the same function to encrypt and decrypt as well! So basically we would expect the second block of ciphertext to just be the plaintext XOR'd with the IV. Some testing proved that our logic was flawed: using the same function worked because of the symmetry of the XOR operation in OFB mode, and not because `IV == AES(AES(IV))` which would break AES OFB. + +Setting the encryption key to NULL on the server seemed easy enough, but sadly this would also mean that the server couldn't decrypt the messages from the client (as this key was used for both encryption and decryption by both sides). + +To understand the next step, let's see how the plaintext is formatted. It consists of some header bytes (including IV and HMAC sign) followed by data. The data is the only part that gets encrypted if encryption is used. This data is essentially an array of different data blocks. The first two bytes of each block are the "TlvType" (an enum in `packets.h`) and the length of the data block (excluding these two bytes). The rest of block is the actual data. It is also essential to understand that AES+OFB generates a bytestream which only depends on the IV and the encryption key. This stream does then get XOR'd with the plaintext. Changing a byte in the plain/ciphertext only changes the corresponding byte in the cipher/plaintext. If we know a byte P from the plaintext, it is easy to substitute it with another byte P': simply change C to C'=C XOR P XOR P'. + +Let's dive back into the code. When trying to dump the flag through an error message (which never gets encrypted) on the client side, we stumbled across some interesting code. + +~~~ c +size_t pos = 0; +while (pos < len && len - pos >= 2) +{ + // Assure there is enough length for the element + if (data[pos + 1] > len - pos - 2) { + send_error(session, "%s: not enough data left for element type %d (need %d bytes but only %d left)\n", + __FUNCTION__, data[pos], data[pos + 1], len - pos - 2); + return -1; + } +~~~ + +This is were our attack will happen. We let the flow described earlier proceed as normal, except we intercept the final message returning the flag to the client. Assume we want to decrypt the fifth byte of the flag. If we manage to set the length of the first datablock to 3, the fifth byte of the flag will be interpreted as the length of the second data block. If this length is greater than the amount of remaining bytes, then our byte will get sent back to the server unencrypted! To do this, we need to know the original length of the flag, which is hardcoded and 39. So we replace the second byte with `C' = C XOR 0x27 XOR 0x3` and this should print the correct byte and the preceding byte. + +However, we're not there yet. All ciphertexts get signed with HMAC_SHA256. At this point, we got stuck for a bit. Around 2.5 hours before the competition ended a hint was posted (see challenge description) which led to the solution. + +~~~ c +static int radium_check_authenticity(struct radium_session *session, struct pkt_header *hdr) +{ + // Nothing to do if no encryption is used, or if it's not an authenticated message + if (!session->using_encryption || hdr->msgtype < Packet_Command) + return 0; + // We need a session key to verify all the other packets + else if (!session->using_encryption || !session->handshake_done) { + fprintf(stderr, "%s: no session key available to check authenticity\n", __FUNCTION__); + return -1; + } + +static int radium_decrypt_data(struct radium_session *session, struct pkt_header *hdr) +{ + // Nothing to do if not encrypted + if (!hdr->encrypted) + return 0; +~~~ + +Basically, the solution was to set the msgtype byte to 0x1 (ServerHello). This wasn't according to our protocol flow, but that didn't matter as we intended to already produce an error during the parsing of the message. Throwing this together revealed that the fifth byte was 'E', which matched our expectation of flag format "CSCBE{.................................}". Jackpot! Now we just had to repeat for all other bytes. A simple [python script](https://zeus.ugent.be/zeuswpi/GotPD6yg.py) solved this. + +Flag: CSCBE{1FFCD19C964D3E5DF5B4CFF490583AC1} diff --git a/content/events/17-18/lasershoot.md b/content/events/17-18/lasershoot.md new file mode 100644 index 0000000..da1567f --- /dev/null +++ b/content/events/17-18/lasershoot.md @@ -0,0 +1,45 @@ +--- +title: Lasershoot +description: Programmeer en speel je eigen lasershoot! +created_at: 03-03-2018 +time: '21-03-2018 18:00' +end: '21-03-2018 23:00' +location: 'Kantoor Delaware: Blue Tower 1 (4th floor)' +locationlink: 'Sluisweg 1, 9000 Ghent Belgium' +color: "#f44336" +header_text_background: false +--- + +**Oproep aan iedereen: jullie hulp is nodig!** + +Wij kregen volgende oproep binnen van Delaware: + +> Dag Zeus, +> +> Delaware organiseert voor het eerste zijn eigen lasershoot! Op basis van enkele sessies met onze collega’s hebben we reeds een prototype gebouwd maar zijn op zoek naar versterking om tot een finaal product te komen. Daarom nodigen we Zeus WPI uit voor een avondje programmeren (en pizza) gevolgd door het spelen van de zelf gebouwde lasershoot. +> +> De basics tot nu toe zijn 2 Raspberry Pi’s met infrarood sensoren die als ‘base’ fungeren & een webapp die verbonden is met een database om zo weer te geven welke base beschoten is. Hieronder de volgende pistes die wij zien als ‘improvements’ waar jullie doorheen de avond aan kunnen werken: +> +> **Basics:** +> +> * Het creëren & testen van fysieke afbakeningen voor de sensoren +> * Scorebord maken voor het spel +> * Pi’s connecteren met een scherm waarop data zal bijgehouden worden +> * Dit scherm zo visueel aantrekkelijk mogelijk maken +> * Programmeren van een ‘shield’ voor de bases zodat hij onraakbaar is +> * Connecteren van de Pi’s aan de hand van een database +> * Misschien een derde Raspberry Pi gebruiken als centrale database +> * Connecteren van laptop met de Pi’s om te gebruiken als controller van de games +> +> **Advanced:** +> +> * Game mode uitbouwen met een centrale pi die paswoorden genereert die de andere ‘unlockt’ om zo punten te scoren +> * Andere game modes +> * Get creative 😊 +> +> Wij verwachten jullie op 21/3 om 18u! Een laptop meebrengen lijkt ons logisch maar als jullie andere materialen (Pi’s, Arduino's, sensoren, …) willen meenemen; feel free! + +Dus aan allen die zich geroepen voelen om ons te vergezellen richting Delaware om hun te helpen deze lasershoot op punt te zetten, schrijf jullie hier in: [https://event.fkgent.be/events/187](https://event.fkgent.be/events/187). + +Haast je! Want de plaatsen zijn beperkt. + diff --git a/content/projects/badass_bottle_bats.md b/content/projects/badass_bottle_bats.md deleted file mode 100644 index e47a20e..0000000 --- a/content/projects/badass_bottle_bats.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: Badass Bottle Bats -github: https://github.com/ZeusWPI/aichallenge -site: https://zeus.ugent.be/bottlebats/ -logo_letter: B -logo_color: "#FFD062" ---- -A bot writing contest. [https://zeus.ugent.be/bottlebats](https://zeus.ugent.be/bottlebats) diff --git a/content/projects/mozaic.md b/content/projects/mozaic.md new file mode 100644 index 0000000..ffd20bf --- /dev/null +++ b/content/projects/mozaic.md @@ -0,0 +1,8 @@ +--- +title: Mozaic +github: https://github.com/ZeusWPI/mozaic +site: https://zeus.ugent.be/bottlebats/ +logo_letter: M +logo_color: "#FFD062" +--- +MOZAIC is the Massive Online Zeus Artificial Intelligence Competition platform. It aims to provide a flexible platform to host your very own AI competition. diff --git a/content/projects/site.md b/content/projects/site.md new file mode 100644 index 0000000..a213ba4 --- /dev/null +++ b/content/projects/site.md @@ -0,0 +1,8 @@ +--- +title: zeus.ugent.be +github: https://github.com/ZeusWPI/zeus.ugent.be +site: https://zeus.ugent.be +logo_letter: Z +logo_color: "#FF7F00" +--- +Even this site is a Zeus project! diff --git a/layouts/partials/_about_sub_navbar.erb b/layouts/partials/_about_sub_navbar.erb index 5dcbe8c..0c4872d 100644 --- a/layouts/partials/_about_sub_navbar.erb +++ b/layouts/partials/_about_sub_navbar.erb @@ -4,6 +4,6 @@
  • Contact
  • Statuten
  • Historiek
  • -
  • Verslagen (soon)
  • +
  • Verslagen
  • diff --git a/lib/filters/pandoc_pdf.rb b/lib/filters/pandoc_pdf.rb new file mode 100644 index 0000000..f66613e --- /dev/null +++ b/lib/filters/pandoc_pdf.rb @@ -0,0 +1,18 @@ +require 'pandoc-ruby' +require 'fileutils' + +class PandocPDF < Nanoc::Filter + identifier :pandoc_pdf + type text: :binary + + def run(content, params = {}) + # https://github.com/nanoc/nanoc/blob/master/nanoc/lib/nanoc/filters/pandoc.rb + args = params.key?(:args) ? params[:args] : params + + args[:o] = output_filename + '.pdf' + + PandocRuby.convert(content, *args) + + FileUtils.mv(output_filename + '.pdf', output_filename) + end +end diff --git a/lib/helpers/preprocess.rb b/lib/helpers/preprocess.rb index bf3f3a4..2d83275 100644 --- a/lib/helpers/preprocess.rb +++ b/lib/helpers/preprocess.rb @@ -68,4 +68,11 @@ module PreprocessHelper event[:end] = DateTime.parse(event[:end]) if event[:end] end end + + def add_report_metadata + @items.find_all('/about/verslagen/*/*').each do |report| + report[:academic_year] = report.identifier.to_s.split('/')[-2] + report[:date] = Date.strptime(report.identifier.without_ext.split('/').last) + end + end end diff --git a/lib/helpers/reports.rb b/lib/helpers/reports.rb new file mode 100644 index 0000000..3e952af --- /dev/null +++ b/lib/helpers/reports.rb @@ -0,0 +1,5 @@ +module ReportsHelper + def reports + @items.find_all('/about/verslagen/*/*').sort_by(&:identifier).reverse + end +end diff --git a/lib/helpers_.rb b/lib/helpers_.rb index 180a4c1..065cccd 100644 --- a/lib/helpers_.rb +++ b/lib/helpers_.rb @@ -21,3 +21,4 @@ include PreprocessHelper include TimeHelper include TileHelper include AboutHelper +include ReportsHelper