From 8e69e5bf42e5eb421ccd7145cb34726f19ec25eb Mon Sep 17 00:00:00 2001 From: Anton Linus Date: Fri, 16 Oct 2020 00:04:12 +0200 Subject: [PATCH] updated map / updated works --- code/esp8266/.DS_Store | Bin 0 -> 6148 bytes website/map/goodscooters.php | 442 ++++++++++++++++++ website/map/index.php | 21 +- works/!Mediengruppe Bitnik/.DS_Store | Bin 0 -> 6148 bytes works/!Mediengruppe Bitnik/desc.txt | 7 + .../follow the rider/otastaImg/DNSServer.cpp | 166 +++++++ .../follow the rider/otastaImg/DNSServer.h | 72 +++ .../follow the rider/otastaImg/data/.DS_Store | Bin 0 -> 6148 bytes .../data}/assets/fruit-shapes.json | 0 .../data}/assets/fruit-sprites.json | 0 .../data}/assets/fruit-sprites.png | Bin .../{ => otastaImg/data}/dist/phaser.min.js | 0 .../{ => otastaImg/data}/dist/reset.css | 0 .../{ => otastaImg/data}/dist/reveal.css | 0 .../{ => otastaImg/data}/dist/reveal.esm.js | 0 .../{ => otastaImg/data}/dist/reveal.js | 0 .../data}/dist/theme/bitnik.css | 0 .../nimbus-sans-l/NimbusSanL-ReguItal.ttf | Bin .../{ => otastaImg/data}/index.html | 0 .../data}/js/components/playback.js | 0 .../{ => otastaImg/data}/js/config.js | 0 .../data}/js/controllers/autoanimate.js | 0 .../data}/js/controllers/backgrounds.js | 0 .../data}/js/controllers/controls.js | 0 .../data}/js/controllers/focus.js | 0 .../data}/js/controllers/fragments.js | 0 .../data}/js/controllers/keyboard.js | 0 .../data}/js/controllers/location.js | 0 .../data}/js/controllers/notes.js | 0 .../data}/js/controllers/overview.js | 0 .../data}/js/controllers/plugins.js | 0 .../data}/js/controllers/pointer.js | 0 .../data}/js/controllers/print.js | 0 .../data}/js/controllers/progress.js | 0 .../data}/js/controllers/slidecontent.js | 0 .../data}/js/controllers/slidenumber.js | 0 .../data}/js/controllers/touch.js | 0 .../{ => otastaImg/data}/js/index.js | 0 .../{ => otastaImg/data}/js/reveal.js | 0 .../{ => otastaImg/data}/js/utils/color.js | 0 .../data}/js/utils/constants.js | 0 .../{ => otastaImg/data}/js/utils/device.js | 0 .../{ => otastaImg/data}/js/utils/loader.js | 0 .../{ => otastaImg/data}/js/utils/util.js | 0 .../{ => otastaImg/data}/main.js | 0 .../{ => otastaImg/data}/make.sh | 0 .../{ => otastaImg/data}/package-lock.json | 0 .../{ => otastaImg/data}/package.json | 0 .../data}/plugin/typed/LICENSE.txt | 0 .../data}/plugin/typed/README.md | 0 .../data}/plugin/typed/typed.js | 0 .../{ => otastaImg/data}/start_server.sh | 0 .../follow the rider/otastaImg/otastaImg.ino | 98 ++++ works/Aram Bartholl/.DS_Store | Bin 6148 -> 6148 bytes works/Aram Bartholl/desc.txt | 7 + .../fossils of late capitalism/.DS_Store | Bin 0 -> 6148 bytes .../fossils of late capitalism/desc.txt | 3 - .../otastaImg/DNSServer.cpp | 166 +++++++ .../otastaImg/DNSServer.h | 72 +++ .../otastaImg/data/.DS_Store | Bin 0 -> 6148 bytes .../data}/fossilsoflatecapitalism.gif | Bin .../otastaImg/data/index.html | 16 + .../otastaImg/otastaImg.ino | 98 ++++ works/JODI/.DS_Store | Bin 0 -> 6148 bytes works/JODI/otastaImg/DNSServer.cpp | 166 +++++++ works/JODI/otastaImg/DNSServer.h | 72 +++ works/JODI/otastaImg/data/.DS_Store | Bin 0 -> 6148 bytes .../data/index.html} | 0 works/JODI/otastaImg/otastaImg.ino | 98 ++++ works/Jonas Lund/.DS_Store | Bin 6148 -> 6148 bytes works/Jonas Lund/hello capitalism/.DS_Store | Bin 0 -> 6148 bytes .../hello capitalism/otastaImg/DNSServer.cpp | 166 +++++++ .../hello capitalism/otastaImg/DNSServer.h | 72 +++ .../hello capitalism/otastaImg/data/.DS_Store | Bin 0 -> 6148 bytes .../{ => otastaImg/data}/index.html | 0 .../{ => otastaImg/data}/jquery.js | 0 .../data}/script_type-retype.js | 0 .../{ => otastaImg/data}/styles-type.css | 0 .../hello capitalism/otastaImg/otastaImg.ino | 98 ++++ works/Martin Howse/.DS_Store | Bin 0 -> 6148 bytes ...les at master · microresearch:notes.webloc | 8 - works/Martin Howse/wokthecables/.DS_Store | Bin 0 -> 6148 bytes works/Martin Howse/wokthecables/DNSServer.cpp | 166 +++++++ works/Martin Howse/wokthecables/DNSServer.h | 72 +++ .../wokthecables/wokthecables.ino | 249 ++++++++++ works/Sofya Aleynikova/followers/.DS_Store | Bin 0 -> 6148 bytes .../followers/otastaImg/.DS_Store | Bin 0 -> 6148 bytes .../followers/otastaImg/DNSServer.cpp | 166 +++++++ .../followers/otastaImg/DNSServer.h | 72 +++ .../followers/otastaImg/data/.DS_Store | Bin 0 -> 6148 bytes .../{ => otastaImg/data}/followers.gif | Bin .../followers/otastaImg/data/index.html | 16 + .../followers/otastaImg/otastaImg.ino | 98 ++++ 93 files changed, 2666 insertions(+), 21 deletions(-) create mode 100644 code/esp8266/.DS_Store create mode 100644 website/map/goodscooters.php create mode 100644 works/!Mediengruppe Bitnik/.DS_Store create mode 100644 works/!Mediengruppe Bitnik/desc.txt create mode 100644 works/!Mediengruppe Bitnik/follow the rider/otastaImg/DNSServer.cpp create mode 100755 works/!Mediengruppe Bitnik/follow the rider/otastaImg/DNSServer.h create mode 100644 works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/.DS_Store rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/assets/fruit-shapes.json (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/assets/fruit-sprites.json (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/assets/fruit-sprites.png (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/dist/phaser.min.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/dist/reset.css (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/dist/reveal.css (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/dist/reveal.esm.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/dist/reveal.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/dist/theme/bitnik.css (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/dist/theme/fonts/nimbus-sans-l/NimbusSanL-ReguItal.ttf (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/index.html (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/components/playback.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/config.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/controllers/autoanimate.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/controllers/backgrounds.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/controllers/controls.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/controllers/focus.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/controllers/fragments.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/controllers/keyboard.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/controllers/location.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/controllers/notes.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/controllers/overview.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/controllers/plugins.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/controllers/pointer.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/controllers/print.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/controllers/progress.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/controllers/slidecontent.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/controllers/slidenumber.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/controllers/touch.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/index.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/reveal.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/utils/color.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/utils/constants.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/utils/device.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/utils/loader.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/js/utils/util.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/main.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/make.sh (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/package-lock.json (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/package.json (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/plugin/typed/LICENSE.txt (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/plugin/typed/README.md (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/plugin/typed/typed.js (100%) rename works/!Mediengruppe Bitnik/follow the rider/{ => otastaImg/data}/start_server.sh (100%) create mode 100644 works/!Mediengruppe Bitnik/follow the rider/otastaImg/otastaImg.ino create mode 100644 works/Aram Bartholl/desc.txt create mode 100644 works/Aram Bartholl/fossils of late capitalism/.DS_Store delete mode 100644 works/Aram Bartholl/fossils of late capitalism/desc.txt create mode 100644 works/Aram Bartholl/fossils of late capitalism/otastaImg/DNSServer.cpp create mode 100755 works/Aram Bartholl/fossils of late capitalism/otastaImg/DNSServer.h create mode 100644 works/Aram Bartholl/fossils of late capitalism/otastaImg/data/.DS_Store rename works/Aram Bartholl/fossils of late capitalism/{ => otastaImg/data}/fossilsoflatecapitalism.gif (100%) create mode 100644 works/Aram Bartholl/fossils of late capitalism/otastaImg/data/index.html create mode 100644 works/Aram Bartholl/fossils of late capitalism/otastaImg/otastaImg.ino create mode 100644 works/JODI/.DS_Store create mode 100644 works/JODI/otastaImg/DNSServer.cpp create mode 100755 works/JODI/otastaImg/DNSServer.h create mode 100644 works/JODI/otastaImg/data/.DS_Store rename works/JODI/{coilww.html => otastaImg/data/index.html} (100%) create mode 100644 works/JODI/otastaImg/otastaImg.ino create mode 100644 works/Jonas Lund/hello capitalism/.DS_Store create mode 100644 works/Jonas Lund/hello capitalism/otastaImg/DNSServer.cpp create mode 100755 works/Jonas Lund/hello capitalism/otastaImg/DNSServer.h create mode 100644 works/Jonas Lund/hello capitalism/otastaImg/data/.DS_Store rename works/Jonas Lund/hello capitalism/{ => otastaImg/data}/index.html (100%) rename works/Jonas Lund/hello capitalism/{ => otastaImg/data}/jquery.js (100%) rename works/Jonas Lund/hello capitalism/{ => otastaImg/data}/script_type-retype.js (100%) rename works/Jonas Lund/hello capitalism/{ => otastaImg/data}/styles-type.css (100%) create mode 100644 works/Jonas Lund/hello capitalism/otastaImg/otastaImg.ino create mode 100644 works/Martin Howse/.DS_Store delete mode 100644 works/Martin Howse/notes:scooter:arduino:wokthecables at master · microresearch:notes.webloc create mode 100644 works/Martin Howse/wokthecables/.DS_Store create mode 100644 works/Martin Howse/wokthecables/DNSServer.cpp create mode 100755 works/Martin Howse/wokthecables/DNSServer.h create mode 100644 works/Martin Howse/wokthecables/wokthecables.ino create mode 100644 works/Sofya Aleynikova/followers/.DS_Store create mode 100644 works/Sofya Aleynikova/followers/otastaImg/.DS_Store create mode 100644 works/Sofya Aleynikova/followers/otastaImg/DNSServer.cpp create mode 100755 works/Sofya Aleynikova/followers/otastaImg/DNSServer.h create mode 100644 works/Sofya Aleynikova/followers/otastaImg/data/.DS_Store rename works/Sofya Aleynikova/followers/{ => otastaImg/data}/followers.gif (100%) create mode 100644 works/Sofya Aleynikova/followers/otastaImg/data/index.html create mode 100644 works/Sofya Aleynikova/followers/otastaImg/otastaImg.ino diff --git a/code/esp8266/.DS_Store b/code/esp8266/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 $id, + "lastPos" => $pos, + "lastLocationUpdate" => $lst, + "isRentable" => $rnt, + "state" => $act, + "name" => $nam, + "title" => $tit, + "desc" => $des); + $id++; + } + + return $latestData; //return array + +} + + +function makeMarker(int $id){ // generate appropriate markers based on latest JSON + + $readJSON = file_get_contents('./latestData.json'); //read latest data + $arr = json_decode($readJSON, true); + + $pos = $arr[$id]["lastPos"]; // get last known position + $lst = $arr[$id]["lastLocationUpdate"]; // get time of last position + $rnt = $arr[$id]["isRentable"]; // check if scooter is rentable, + $act = $arr[$id]["state"]; // check if scooter is ACTIVE or MAINTAINANCE + // access values from the multidimensional $scooters array + $nam = $arr[$id]["name"]; // get the artist name + $tit = $arr[$id]["title"]; // get the works title + $des = $arr[$id]["desc"]; // get the works description + + + + //check scooter status and construct marker with corresponding icon + + //check if scooter is rentable + if($rnt == true && $act === 'ACTIVE'){ + $marker = 'var scooter'.$id.' = L.marker(['.$pos.'], {time: "'.$lst.'"}).addTo(map) + .bindPopup("'.$tit.'
'.$des.'
Last updated: '.$lst=str_replace(array('T', 'Z'), ' ', $lst).'
Status: rentable, Gallery available") + .bindTooltip("'.$nam.'").setIcon(availableIcon);'; + + } elseif ($rnt == false && $act === 'ACTIVE') { + $marker = 'var scooter'.$id.' = L.marker(['.$pos.'], {time: "'.$lst.'"}).addTo(map) + .bindPopup("'.$tit.'
'.$des.'
Last updated: '.$lst=str_replace(array('T', 'Z'), ' ', $lst).'
Status: rented Out, Gallery unavailable") + .bindTooltip("'.$nam.'").setIcon(isRentedIcon);'; + + }; + //check if scooter is in maintenace + if($act !== "ACTIVE"){ + $marker = 'var scooter'.$id.' = L.marker(['.$pos.'], {time: "'.$lst.'"}).addTo(map) + .bindPopup("'.$tit.'
'.$des.'
Last updated: '.$lst=str_replace(array('T', 'Z'), ' ', $lst).'
Status: unavailable, in maintenace") + .bindTooltip("'.$nam.'").setIcon(isMaintenanceIcon);'; + }; + + return $marker; + + +} + + +function appendJSON($filename, $data){ // create historical json data for documentation over time + + // read the file if present + $handle = @fopen($filename, 'r+'); + + // create the file if needed + if ($handle === null) + { + $handle = fopen($filename, 'w+'); + } + + if ($handle) + { + // seek to the end + fseek($handle, 0, SEEK_END); + + // are we at the end of is the file empty + if (ftell($handle) > 0) + { + // move back a byte + fseek($handle, -1, SEEK_END); + + // add the trailing comma + fwrite($handle, ',', 1); + + // add the new json string + fwrite($handle, json_encode($data) . ']'); + } + else + { + // write the first event inside an array + fwrite($handle, json_encode(array($data))); + } + + // close the handle on the file + fclose($handle); + } + + +} + + + +function callAPI($url){ + $curl = curl_init($url); + curl_setopt($curl, CURLOPT_FAILONERROR, true); + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($curl, CURLOPT_HTTPHEADER, array( + 'x-api-key: bpEUTJEBTf74oGRWxaIcW7aeZMzDDODe1yBoSxi2', + 'Content-Type: application/json', + )); // set the api key + curl_setopt($curl, CURLOPT_USERAGENT,'ProductionRelease/3.8.2 (app.tier.sharing; build:3.8.2.0; iOS 12.4.4) Alamofire/4.9.1'); // set user-agent to that of the Tier.app, sniffed by burpsuite + + $result = curl_exec($curl); + if(!$result){die("Connection Failure");} + curl_close($curl); + return $result; +} + + + +?> + + + + + + OPENCOIL + + + + + + + + + + + + + + + + + + + +
+
+

OPENCOIL

+

a roaming speedshow

+ +
+ info + about + contact +
+
+
+
+
X
+
+

+ OPENCOIL - a roaming speedshow

+ curated by Dennis de Bel & Anton Jehle

+ Impressum

+ + Zentrum für Netzkunst e.V.
+ c/o Robert Sakrowski
+ Kollwitzstraße 71
+ 10435 Berlin

+ Register-Eintrag Nr.: VR 38280 B
+ Steuernummer 27/647/51440 +
+

+
+
+
+
X
+
+

+ Generelle Anfragen / general inquiries

+ mail@opencoil.show

+ Technischer Support / technical support

+ Mail: service@opencoil.show
+ Telegram: https://t.me/opencoil

+ Zentrum für Netzkunst

+ Werkstatt Haus der Statistik
+ Karl-Marx-Allee 1, Haus D
+ 10178 Berlin
+ info@netart.berlin + +

+ +
+
+
+
X
+
EN
+
+

+ OPENCOIL – a roaming Speedshow

+ + Die Ausstellung OPENCOIL setzt sich mit den Auswirkungen von Mikro-Mobilitätsdiensten auf den Stadtraum auseinander, indem sie ihre dezentrale Infrastruktur als Ausstellungsraum nutzt und gleichzeitig die Bedingungen und Auswirkungen dieser Infrastrukturen auch zum Thema macht. + +

+ 11 Künstler*innen wurden eingeladen, ihre Arbeiten auf einem kleinen Wifi Controller mit ~2MB Offline-Speicher zu präsentieren. + +

+ Diese „digitalen Galerieräume“ werden an 11 zufällig ausgewählten E-Scootern angebracht. + +
+ + So fährt die Ausstellung, von den Nutzer*Innen der Roller unbemerkt, als „roaming Speedshow“ durch die Stadt. + +

+ Der aktuelle Standort der Kunstwerke kann ab dem 26. Oktober über diese Website verfolgt werden. Damit die Werke betrachtet werden können, muss die „Roller-Galerie“ im Stadtraum gefunden werden. + +

+ Sobald der Roller angemietet ist, erhalten die Besucher*innen über ihr persönliches Smartphone, Zugang zu dem 2MB großen Galerieraum und den ausgestellten Werken. +

+ Während Kapazitätsbeschränkungen und die bevorzugte Vermeidung von Zusammenkünften in geschlossenen Räumen, traditionelle Galerien und Museen vor Herausforderungen stellen, zielt OPENCOIL darauf ab, die Ortsunabhängigkeit des Online mit der Materialität des Offline (und umgekehrt) zu verbinden. Die Infrastruktur der „Mikro-Mobiltitätsdienste“ wird übernommen – klimaneutral und dezentral. +

+ Die Gehwege vieler Städte auf der ganzen Welt wurden in den letzten Jahren von sogenannten 'dockless sharing vehicles' regelrecht überflutet. Mit Versprechungen von Umweltfreundlichkeit und Elektromobilität, besetzten diese Risikokapitalismus Aktivisten die Grauzone zwischen privatem und öffentlichem Raum auf den Straßen unserer Städte. Diese gewissenlose Gewissenhaftigkeit der "Mikro-Mobilitätsdienste" wirft jedoch wichtige Fragen zu städtischem Raum, Eigentum, Agentur, Produktion, Ökologie und sehr spätem Kapitalismus auf. +

+ Wie umgehen mit der Inbesitznahme öffentlichen Raums?
+ Welche Werkzeuge und Wege gibt es sich diesen zurückzuerobern?
+
+ OPENCOIL soll nicht nur ein Pandemie-tauglicher Weg sein, um Kunst im öffentlichen Offline-Raum zu zeigen. OPENCOIL ist auch eine kreative (Um-)Nutzung von E-Scootern, ein Versuch, sich ihnen mit künstlerischen Mitteln zu nähern. +
+ Gezeigt werden Arbeiten, die sich mit Fragen der Überschneidung von öffentlichem und privatem Raum, dem Umgang mit Ressourcen sowie mit Greenwashing, Risikokapitalismus und Vandalismus befassen. +

+ Die teilnehmenden Künstler*innen sind: +

+ Aram Bartholl
+ Constant Dullaart
+ Dennis de Bel & Anton Jehle
+ JODI
+ Jonas Lund
+ Martin Howse
+ !Mediengruppe Bitnik
+ Rosa Menkman
+ Sarah Grant
+ Sofya Aleynikova
+ Danja Vasiliev
+

+ Sonstige Erläuterungen: +

+ Die künstlerischen Beiträge sind jeweils auf einem Wifi Mikrocontroller gespeichert, welcher mit einem Tretroller verbunden ist und so, sobald der Roller ausgeliehen ist, mit Strom versorgt wird. Um die Arbeiten zu sehen verbindet man sich mit dem vom Wifi Chip gesendeten, lokalen unverschlüsselten WiFi Netzwerk. Es öffnet sich automatisch ein Webportal, indem die Arbeit zu sehen ist. Es ist keine mobile Datenverbindung notwendig. + Alle Arbeiten wurden von den Künstler*innen speziell für die Betrachtung auf Smartphones optimiert. +

+ OPENCOIL ist in keiner Weise mit der den „Mikro-Mobilitätsdiensten“ assoziiert, sondern bedient sich lediglich am bestehenden Rollernetzwerk. Die Umnutzung der Roller zu einem Ausstellungsort ist nach der Ausstellung komplett reversibel und schränkt den herkömmlichen Gebrauch der Roller (auch während der Ausstellung) in keiner Weise ein. Die Roller werden nicht beschädigt.

+ Die Ausstellung startet am 26. Oktober auf dem öffentlichen Platz vor dem Zentrum für Netzkunst (Haus der Statistik) und wird in der Woche bis zum 1. November täglich von unserem Team gewartet und am Laufen gehalten. Sollte eine Arbeit beschädigt oder nicht auffindbar sein bitte per Mail (service@opencoil.show) oder über die Telegram App (https://t.me/opencoil)

+

+
less info
+
+
+
X
+

+ OPENCOIL - a roaming speed show +

+ The OPENCOIL exhibition explores the impact of micro-mobility services on urban space by using its decentralised infrastructure as an exhibition space, while also addressing the conditions and effects of this infrastructure. +

+ 11 artists were invited to present their work on a small Wifi controller with ~2MB offline memory. +

+ These "digital gallery spaces" are attached to 11 randomly selected e-scooters. + Thus the exhibition, unnoticed by the regular users of these scooters, drives through the city as a "roaming speed show". +

+ From October 26th onwards the current location of the artworks will be displayed here on this website. In order to view the works the corresponding "Scooter Gallery" must be found in the offline urban space. +

+ Once the scooter is rented, visitors will be able to access the 2MB gallery space and the exhibited works via their personal smartphone. +

+ While capacity restrictions and the preferred avoidance of gatherings in closed spaces pose challenges on traditional galleries and museums, OPENCOIL aims to combine the independence of the online with the materiality of the offline (and vice versa). The infrastructure of "micro-mobility services" will be taken over - climate-neutral and decentralised. +

+ The pavements of many cities around the world have been flooded in recent years by so-called 'dockless sharing vehicles'. With promises of eco-friendliness and electromobility, these risk capitalism activists have occupied the grey zone between private and public space on the streets of our cities. However, this unscrupulous conscientiousness of 'micro-mobility services' raises important questions about urban space, ownership, agency, production, ecology and very late capitalism. +

+ How to deal with the occupation of public space? + What tools and ways are there to reclaim it? +

+ OPENCOIL is not only meant to be a pandemic-proof way to show art in public offline space. OPENCOIL is also a creative (re)use of e-scooters, an attempt to approach them by artistic means. + On show are works that deal with questions of the overlap between public and private space, the use of resources, as well as greenwashing, risk capitalism and vandalism. +

+ The participating artists are: +

+ Aram Bartholl
+ Constant Dullaart
+ Dennis de Bel & Anton Jehle
+ JODI
+ Jonas Lund
+ Martin Howse
+ !Mediengruppe Bitnik
+ Rosa Menkman
+ Sarah Grant
+ Sofya Aleynikova
+ Danja Vasiliev
+


+ + Other explanatory notes: +

+ The artistic contributions are each stored on a Wifi microcontroller, which is connected to a scooter and is thus supplied with power as soon as the scooter is rented. To view the works, you connect to the local unencrypted WiFi network sent by the Wifi chip. A web portal opens automatically, where the work can be viewed. No mobile data connection is necessary. All works have been specially optimised by the artists to be viewed on smartphones. +

+ OPENCOIL is in no way associated with the "micro-mobility services", but only uses the existing scooter network. The conversion of the scooters into an exhibition space is completely reversible after the exhibition ends and in no way restricts the conventional use of the scooters (even during the exhibition). The scooters will not be damaged. +

+ The exhibition will start on October 26th in the public space in front of Zentrum für Netzkunst (Haus der Statistik). For one week, until November 1st, the exhibition will be serviced and kept running daily by our team. Should a work be damaged or not be found, please send an e-mail (service@opencoil.show) or use the Telegram App (https://t.me/opencoil) +

+
less info
+
+ + + + \ No newline at end of file diff --git a/website/map/index.php b/website/map/index.php index 197feeb..eb21330 100644 --- a/website/map/index.php +++ b/website/map/index.php @@ -6,16 +6,17 @@ $scooters = array( //array('https://opencoil.show/test-json.php?scooterID=1', 'artist name 0', 'title 0', 'desciption 0' ), //array('https://opencoil.show/test-json.php?scooterID=2', 'artist name 1', 'title 1', 'desciption 1' ), //array('https://opencoil.show/test-json.php?scooterID=3', 'artist name 2', 'title 2', 'desciption 2' ), - array('https://platform.tier-services.io/v1/vehicle/fbd739d6-554f-4eaf-bd9c-afe3d501c94b', 'artist name 0', 'title', 'desciption'), - array('https://platform.tier-services.io/v1/vehicle/530b66c9-e5f9-47ac-ba31-2e357dc4c735', 'artist name 1', 'title', 'desciption'), - array('https://platform.tier-services.io/v1/vehicle/aa9cedf8-ab8e-4651-8b43-93079179f26a', 'artist name 2', 'title', 'desciption'), - array('https://platform.tier-services.io/v1/vehicle/9df16c74-4a88-4f21-acf5-12ba401ca15a', 'artist name 3', 'title', 'desciption'), - array('https://platform.tier-services.io/v1/vehicle/4763ce60-5b2e-44cf-919e-fffbff26a15e', 'artist name 4', 'title', 'desciption'), - array('https://platform.tier-services.io/v1/vehicle/ca884ba2-b0a6-4f3f-b727-fcc33d10182c', 'artist name 5', 'title', 'desciption'), - array('https://platform.tier-services.io/v1/vehicle/78e9b9f1-0cf1-4415-9301-e2fe01d39bce', 'artist name 6', 'title', 'desciption'), - array('https://platform.tier-services.io/v1/vehicle/0b939caf-80e9-4d6b-8454-4a7f8eaf088c', 'artist name 7', 'title', 'desciption'), - array('https://platform.tier-services.io/v1/vehicle/0f7fa267-4bc1-439a-8fd0-43b98b9ffba7', 'artist name 8', 'title', 'desciption'), - array('https://platform.tier-services.io/v1/vehicle/8732f342-df2f-475f-b0f6-c0032743a944', 'artist name 9', 'title', 'desciption'), + array('https://platform.tier-services.io/v1/vehicle/1cdccfec-60c3-4b9e-ad18-40861a3a9ab2', 'Aram Bartholl', 'Fossils of late capitalism', 'Aram Bartholl has salvaged rental bikes and scooters from the Spree River and is now exhibiting them as material relics of the platform economy.'), + array('https://platform.tier-services.io/v1/vehicle/ec9437d8-b105-4c94-bcdd-8653f629d476', '!Mediengruppe Bitnik', 'Follow the Rider ƪ(ړײ)ƪ', 'Follow the next person you see on an e-scooter. 👠 Keep distance but don\'t lose your guide.'), + array('https://platform.tier-services.io/v1/vehicle/bfe887ad-cb89-4311-836f-dfb804b46269', 'Jonas Lund', 'Hello Capitalism', '\'Hello Capitalism\' is a text-based work by Jonas Lund, exploring a wide range of different types of capitalistic systems.'), + array('https://platform.tier-services.io/v1/vehicle/808decca-3537-41ad-96c0-45f29c57349d', 'Martin Howse', 'wok_the_cables', 'Adventure game for psychogeophysical divination of portals, realtime instructions to follow #wokthecables'), + array('https://platform.tier-services.io/v1/vehicle/54aaed50-dd24-4c10-9580-b05b3bfc6985', 'Sofya Aleynikova', 'followers', 'Eine weibliche Protagonistin manifestiert sich als Meme im Web und stellt die richtigen Fragen.'), + array('https://platform.tier-services.io/v1/vehicle/d794fac2-5c3e-4f2b-aed1-f70ef82f67d8', 'JODI', '%Location????????', 'XXXXXXXXXXXXXX'), + array('https://platform.tier-services.io/v1/vehicle/86219ae1-416a-4b36-897a-c738397d7210', 'Rosa Menkmann', 'title', 'desciption'), + array('https://platform.tier-services.io/v1/vehicle/0b939caf-80e9-4d6b-8454-4a7f8eaf088c', 'Sarah Grant', 'title', 'desciption'), + array('https://platform.tier-services.io/v1/vehicle/0f7fa267-4bc1-439a-8fd0-43b98b9ffba7', 'Danja Vasiliev', 'title', 'desciption'), + array('https://platform.tier-services.io/v1/vehicle/8732f342-df2f-475f-b0f6-c0032743a944', 'Constant Dullaart', 'clock', 'ssid that tells the time'), + array('https://platform.tier-services.io/v1/vehicle/511c3984-3f81-4022-acc2-8e22646a5e01', 'Dennis de Bel & Anton Jehle', 'Paracity Gallery v0.41', 'HOW TO: diy scooter gallery'), ); diff --git a/works/!Mediengruppe Bitnik/.DS_Store b/works/!Mediengruppe Bitnik/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 +#include + +#define DEBUG +#define DEBUG_OUTPUT Serial + +DNSServer::DNSServer() +{ + _ttl = htonl(60); + _errorReplyCode = DNSReplyCode::NonExistentDomain; +} + +bool DNSServer::start(const uint16_t &port, const String &domainName, + const IPAddress &resolvedIP) +{ + _port = port; + _domainName = domainName; + _resolvedIP[0] = resolvedIP[0]; + _resolvedIP[1] = resolvedIP[1]; + _resolvedIP[2] = resolvedIP[2]; + _resolvedIP[3] = resolvedIP[3]; + downcaseAndRemoveWwwPrefix(_domainName); + return _udp.begin(_port) == 1; +} + +void DNSServer::setErrorReplyCode(const DNSReplyCode &replyCode) +{ + _errorReplyCode = replyCode; +} + +void DNSServer::setTTL(const uint32_t &ttl) +{ + _ttl = htonl(ttl); +} + +void DNSServer::stop() +{ + _udp.stop(); +} + +void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName) +{ + domainName.toLowerCase(); + domainName.replace("www.", ""); + domainName.replace("https://", ""); +} + +void DNSServer::processNextRequest() +{ + _currentPacketSize = _udp.parsePacket(); + if (_currentPacketSize) + { + _buffer = (unsigned char*)malloc(_currentPacketSize * sizeof(char)); + _udp.read(_buffer, _currentPacketSize); + _dnsHeader = (DNSHeader*) _buffer; + + if (_dnsHeader->QR == DNS_QR_QUERY && + _dnsHeader->OPCode == DNS_OPCODE_QUERY && + requestIncludesOnlyOneQuestion() && + (_domainName == "*" || getDomainNameWithoutWwwPrefix() == _domainName) + ) + + { + replyWithIP(); + } + else if (_dnsHeader->QR == DNS_QR_QUERY) + { + replyWithCustomCode(); + } + + free(_buffer); + } +} + +bool DNSServer::requestIncludesOnlyOneQuestion() +{ + return ntohs(_dnsHeader->QDCount) == 1 && + _dnsHeader->ANCount == 0 && + _dnsHeader->NSCount == 0 && + _dnsHeader->ARCount == 0; +} + +String DNSServer::getDomainNameWithoutWwwPrefix() +{ + String parsedDomainName = ""; + unsigned char *start = _buffer + 12; + if (*start == 0) + { + return parsedDomainName; + } + int pos = 0; + while(true) + { + unsigned char labelLength = *(start + pos); + for(int i = 0; i < labelLength; i++) + { + pos++; + parsedDomainName += (char)*(start + pos); + } + pos++; + if (*(start + pos) == 0) + { + downcaseAndRemoveWwwPrefix(parsedDomainName); + return parsedDomainName; + } + else + { + parsedDomainName += "."; + } + } +} + +void DNSServer::replyWithIP() +{ + _dnsHeader->QR = DNS_QR_RESPONSE; + _dnsHeader->ANCount = _dnsHeader->QDCount; + _dnsHeader->QDCount = _dnsHeader->QDCount; + //_dnsHeader->RA = 1; + + _udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); + _udp.write(_buffer, _currentPacketSize); + + _udp.write((uint8_t)192); // answer name is a pointer + _udp.write((uint8_t)12); // pointer to offset at 0x00c + + _udp.write((uint8_t)0); // 0x0001 answer is type A query (host address) + _udp.write((uint8_t)1); + + _udp.write((uint8_t)0); //0x0001 answer is class IN (internet address) + _udp.write((uint8_t)1); + + _udp.write((unsigned char*)&_ttl, 4); + + // Length of RData is 4 bytes (because, in this case, RData is IPv4) + _udp.write((uint8_t)0); + _udp.write((uint8_t)4); + _udp.write(_resolvedIP, sizeof(_resolvedIP)); + _udp.endPacket(); + + + + #ifdef DEBUG + DEBUG_OUTPUT.print("DNS responds: "); + DEBUG_OUTPUT.print(_resolvedIP[0]); + DEBUG_OUTPUT.print("."); + DEBUG_OUTPUT.print(_resolvedIP[1]); + DEBUG_OUTPUT.print("."); + DEBUG_OUTPUT.print(_resolvedIP[2]); + DEBUG_OUTPUT.print("."); + DEBUG_OUTPUT.print(_resolvedIP[3]); + DEBUG_OUTPUT.print(" for "); + DEBUG_OUTPUT.println(getDomainNameWithoutWwwPrefix()); + #endif +} + +void DNSServer::replyWithCustomCode() +{ + _dnsHeader->QR = DNS_QR_RESPONSE; + _dnsHeader->RCode = (unsigned char)_errorReplyCode; + _dnsHeader->QDCount = 0; + + _udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); + _udp.write(_buffer, sizeof(DNSHeader)); + _udp.endPacket(); +} diff --git a/works/!Mediengruppe Bitnik/follow the rider/otastaImg/DNSServer.h b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/DNSServer.h new file mode 100755 index 0000000..2bade4b --- /dev/null +++ b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/DNSServer.h @@ -0,0 +1,72 @@ +#ifndef DNSServer_h +#define DNSServer_h +#include + +#define DNS_QR_QUERY 0 +#define DNS_QR_RESPONSE 1 +#define DNS_OPCODE_QUERY 0 + +enum class DNSReplyCode +{ + NoError = 0, + FormError = 1, + ServerFailure = 2, + NonExistentDomain = 3, + NotImplemented = 4, + Refused = 5, + YXDomain = 6, + YXRRSet = 7, + NXRRSet = 8 +}; + +struct DNSHeader +{ + uint16_t ID; // identification number + unsigned char RD : 1; // recursion desired + unsigned char TC : 1; // truncated message + unsigned char AA : 1; // authoritive answer + unsigned char OPCode : 4; // message_type + unsigned char QR : 1; // query/response flag + unsigned char RCode : 4; // response code + unsigned char Z : 3; // its z! reserved + unsigned char RA : 1; // recursion available + uint16_t QDCount; // number of question entries + uint16_t ANCount; // number of answer entries + uint16_t NSCount; // number of authority entries + uint16_t ARCount; // number of resource entries +}; + +class DNSServer +{ + public: + DNSServer(); + void processNextRequest(); + void setErrorReplyCode(const DNSReplyCode &replyCode); + void setTTL(const uint32_t &ttl); + + // Returns true if successful, false if there are no sockets available + bool start(const uint16_t &port, + const String &domainName, + const IPAddress &resolvedIP); + // stops the DNS server + void stop(); + + private: + WiFiUDP _udp; + uint16_t _port; + String _domainName; + unsigned char _resolvedIP[4]; + int _currentPacketSize; + unsigned char* _buffer; + DNSHeader* _dnsHeader; + uint32_t _ttl; + DNSReplyCode _errorReplyCode; + + void downcaseAndRemoveWwwPrefix(String &domainName); + String getDomainNameWithoutWwwPrefix(); + bool requestIncludesOnlyOneQuestion(); + void replyWithIP(); + void replyWithCustomCode(); +}; +#endif + diff --git a/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/.DS_Store b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..4df10455818990b6836e6fee6943ca41cd359724 GIT binary patch literal 6148 zcmeHKOHRWu5FNJ>Dq_<`7c4Eo1$qG#s`LP;2cVRo0!m1vw)-4}4L5)*a1}1V5qL8; zQJvIchY*^n?B~qKW52j|Ohjh3%cn$RA{wDE4vtYB5Vmva$-rwk*hn8++7#>Q;^t>p}ubdV>vni?^{tQOlbA>@u?2Y&rWrifRM3vr znB`M2M|#2kC$vZM27N^G2R^|#=#|Hzq6{bl$^h>qoWgui==pM&>{?Ft0|1e0OlmTVnUol{kY>~|{C4aW|CdX&3MOmV- ouwUb_4M9VWV)*h=e2O9hz2ycl_1HLs2BIGVLW5Syz^^j!1rE%04gdfE literal 0 HcmV?d00001 diff --git a/works/!Mediengruppe Bitnik/follow the rider/assets/fruit-shapes.json b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/assets/fruit-shapes.json similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/assets/fruit-shapes.json rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/assets/fruit-shapes.json diff --git a/works/!Mediengruppe Bitnik/follow the rider/assets/fruit-sprites.json b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/assets/fruit-sprites.json similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/assets/fruit-sprites.json rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/assets/fruit-sprites.json diff --git a/works/!Mediengruppe Bitnik/follow the rider/assets/fruit-sprites.png b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/assets/fruit-sprites.png similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/assets/fruit-sprites.png rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/assets/fruit-sprites.png diff --git a/works/!Mediengruppe Bitnik/follow the rider/dist/phaser.min.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/dist/phaser.min.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/dist/phaser.min.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/dist/phaser.min.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/dist/reset.css b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/dist/reset.css similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/dist/reset.css rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/dist/reset.css diff --git a/works/!Mediengruppe Bitnik/follow the rider/dist/reveal.css b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/dist/reveal.css similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/dist/reveal.css rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/dist/reveal.css diff --git a/works/!Mediengruppe Bitnik/follow the rider/dist/reveal.esm.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/dist/reveal.esm.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/dist/reveal.esm.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/dist/reveal.esm.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/dist/reveal.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/dist/reveal.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/dist/reveal.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/dist/reveal.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/dist/theme/bitnik.css b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/dist/theme/bitnik.css similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/dist/theme/bitnik.css rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/dist/theme/bitnik.css diff --git a/works/!Mediengruppe Bitnik/follow the rider/dist/theme/fonts/nimbus-sans-l/NimbusSanL-ReguItal.ttf b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/dist/theme/fonts/nimbus-sans-l/NimbusSanL-ReguItal.ttf similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/dist/theme/fonts/nimbus-sans-l/NimbusSanL-ReguItal.ttf rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/dist/theme/fonts/nimbus-sans-l/NimbusSanL-ReguItal.ttf diff --git a/works/!Mediengruppe Bitnik/follow the rider/index.html b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/index.html similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/index.html rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/index.html diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/components/playback.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/components/playback.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/components/playback.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/components/playback.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/config.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/config.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/config.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/config.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/controllers/autoanimate.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/autoanimate.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/controllers/autoanimate.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/autoanimate.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/controllers/backgrounds.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/backgrounds.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/controllers/backgrounds.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/backgrounds.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/controllers/controls.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/controls.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/controllers/controls.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/controls.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/controllers/focus.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/focus.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/controllers/focus.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/focus.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/controllers/fragments.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/fragments.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/controllers/fragments.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/fragments.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/controllers/keyboard.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/keyboard.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/controllers/keyboard.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/keyboard.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/controllers/location.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/location.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/controllers/location.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/location.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/controllers/notes.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/notes.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/controllers/notes.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/notes.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/controllers/overview.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/overview.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/controllers/overview.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/overview.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/controllers/plugins.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/plugins.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/controllers/plugins.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/plugins.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/controllers/pointer.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/pointer.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/controllers/pointer.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/pointer.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/controllers/print.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/print.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/controllers/print.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/print.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/controllers/progress.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/progress.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/controllers/progress.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/progress.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/controllers/slidecontent.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/slidecontent.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/controllers/slidecontent.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/slidecontent.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/controllers/slidenumber.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/slidenumber.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/controllers/slidenumber.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/slidenumber.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/controllers/touch.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/touch.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/controllers/touch.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/controllers/touch.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/index.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/index.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/index.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/index.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/reveal.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/reveal.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/reveal.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/reveal.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/utils/color.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/utils/color.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/utils/color.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/utils/color.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/utils/constants.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/utils/constants.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/utils/constants.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/utils/constants.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/utils/device.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/utils/device.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/utils/device.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/utils/device.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/utils/loader.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/utils/loader.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/utils/loader.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/utils/loader.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/js/utils/util.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/utils/util.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/js/utils/util.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/js/utils/util.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/main.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/main.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/main.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/main.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/make.sh b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/make.sh similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/make.sh rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/make.sh diff --git a/works/!Mediengruppe Bitnik/follow the rider/package-lock.json b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/package-lock.json similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/package-lock.json rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/package-lock.json diff --git a/works/!Mediengruppe Bitnik/follow the rider/package.json b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/package.json similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/package.json rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/package.json diff --git a/works/!Mediengruppe Bitnik/follow the rider/plugin/typed/LICENSE.txt b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/plugin/typed/LICENSE.txt similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/plugin/typed/LICENSE.txt rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/plugin/typed/LICENSE.txt diff --git a/works/!Mediengruppe Bitnik/follow the rider/plugin/typed/README.md b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/plugin/typed/README.md similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/plugin/typed/README.md rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/plugin/typed/README.md diff --git a/works/!Mediengruppe Bitnik/follow the rider/plugin/typed/typed.js b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/plugin/typed/typed.js similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/plugin/typed/typed.js rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/plugin/typed/typed.js diff --git a/works/!Mediengruppe Bitnik/follow the rider/start_server.sh b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/start_server.sh similarity index 100% rename from works/!Mediengruppe Bitnik/follow the rider/start_server.sh rename to works/!Mediengruppe Bitnik/follow the rider/otastaImg/data/start_server.sh diff --git a/works/!Mediengruppe Bitnik/follow the rider/otastaImg/otastaImg.ino b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/otastaImg.ino new file mode 100644 index 0000000..b786dc5 --- /dev/null +++ b/works/!Mediengruppe Bitnik/follow the rider/otastaImg/otastaImg.ino @@ -0,0 +1,98 @@ + // Captive portal with (arduino) OTA + SPIFFS + + #include + #include + #include + #include + #include // Over-the-Air updates + #include + #include "./DNSServer.h" // Dns server + #include // SPIFFS + + DNSServer dnsServer; + const byte DNS_PORT = 53; + + ESP8266WebServer server(80); + + #ifndef STASSID + #define STASSID "\xF0\x9F\x9B\xB4 UNFLASHED" + //#define STASPSK "mypassword" + #endif + + IPAddress apIP(192, 168, 4, 1); + const char* ssid = STASSID; + //const char* password = STAPSK; + + void setup() { + Serial.begin(115200); + Serial.println("Booting"); + + WiFi.mode(WIFI_AP); + WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); + WiFi.softAP(ssid); + dnsServer.start(DNS_PORT, "*", apIP); // redirect dns request to AP ip + + MDNS.begin("esp8266", WiFi.softAPIP()); + Serial.println("Ready"); + Serial.print("IP address: "); + Serial.println(WiFi.softAPIP()); + + //Over-the-Air updates + ArduinoOTA.setHostname("ESP8266"); + //ArduinoOTA.setPassword("change-me"); //disabled to allow data uploads + ArduinoOTA.begin(); + SPIFFS.begin(); + + //redirect all traffic to index.html + server.onNotFound([]() { + if(!handleFileRead(server.uri())){ + const char *metaRefreshStr = "

redirecting...

"; + server.send(200, "text/html", metaRefreshStr); + } + }); + + server.begin(); + + } + + void loop() { + dnsServer.processNextRequest(); + ArduinoOTA.handle(); + server.handleClient(); + delay(50); + } + + +String getContentType(String filename){ + if(server.hasArg("download")) return "application/octet-stream"; + else if(filename.endsWith(".htm")) return "text/html"; + else if(filename.endsWith(".html")) return "text/html"; + else if(filename.endsWith(".css")) return "text/css"; + else if(filename.endsWith(".js")) return "application/javascript"; + else if(filename.endsWith(".png")) return "image/png"; + else if(filename.endsWith(".gif")) return "image/gif"; + else if(filename.endsWith(".jpg")) return "image/jpeg"; + else if(filename.endsWith(".ico")) return "image/x-icon"; + else if(filename.endsWith(".xml")) return "text/xml"; + else if(filename.endsWith(".mp4")) return "video/mp4"; + else if(filename.endsWith(".pdf")) return "application/x-pdf"; + else if(filename.endsWith(".zip")) return "application/x-zip"; + else if(filename.endsWith(".gz")) return "application/x-gzip"; + return "text/plain"; +} + +//Given a file path, look for it in the SPIFFS file storage. Returns true if found, returns false if not found. +bool handleFileRead(String path){ + if(path.endsWith("/")) path += "index.html"; + String contentType = getContentType(path); + String pathWithGz = path + ".gz"; + if(SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)){ + if(SPIFFS.exists(pathWithGz)) + path += ".gz"; + File file = SPIFFS.open(path, "r"); + size_t sent = server.streamFile(file, contentType); + file.close(); + return true; + } + return false; +} diff --git a/works/Aram Bartholl/.DS_Store b/works/Aram Bartholl/.DS_Store index 56c98cbc29d930f006f3db7e61925db145577aa8..6b14b52671ebb2987faeea12930867a07f2e22e7 100644 GIT binary patch delta 67 zcmZoMXfc=|#>B)qu~2NHo+2a5#(>?7j4YEUvRZ6zWNl;G*kH@NnVo~51E^%PAjfy+ V$^0UY91K9f$iTp|IYML&GXPgW59|N{ delta 335 zcmZoMXfc=|#>B!ku~2NHo+2ab#(>?7iyfGm7+EJTV6v!BDlaZb%E?b+U|{%}RFIQd zTw-8wlaYy;g_Vt+gOiJkhl`6#K#(UkI3vG2xFoTpwAd-JC>qSmOi4|GvI7!JGGOeG z{QMj^J25FNGqpTkK*TveuOu-uFSQ6sYfN}%eO^j_xl?{=UP^IHFvP&{%#@OhcmdIX zqSP{=-hjls)UeFr%%sem%#un@P7Y2^&UgWd>S{wna~%a^Bhy+Pg=%wi104ku6NB1X zfms|J(we4@zL5pBU5gekS-Ncbio-{Nz5@bAMhMLy45b+u*deTAps?8N!qmpJnVo~5 c0~lPJ4Vk|)Pv#eK@A+m-U0AJ@|O#lD@ diff --git a/works/Aram Bartholl/desc.txt b/works/Aram Bartholl/desc.txt new file mode 100644 index 0000000..dc23b29 --- /dev/null +++ b/works/Aram Bartholl/desc.txt @@ -0,0 +1,7 @@ +title: Fossils of late capitalism + + +short: Aram Bartholl has salvaged rental bikes and scooters from the Spree River and is now exhibiting them as material relics of the platform economy. + +gif +aram bartholl 2020 \ No newline at end of file diff --git a/works/Aram Bartholl/fossils of late capitalism/.DS_Store b/works/Aram Bartholl/fossils of late capitalism/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 +#include + +#define DEBUG +#define DEBUG_OUTPUT Serial + +DNSServer::DNSServer() +{ + _ttl = htonl(60); + _errorReplyCode = DNSReplyCode::NonExistentDomain; +} + +bool DNSServer::start(const uint16_t &port, const String &domainName, + const IPAddress &resolvedIP) +{ + _port = port; + _domainName = domainName; + _resolvedIP[0] = resolvedIP[0]; + _resolvedIP[1] = resolvedIP[1]; + _resolvedIP[2] = resolvedIP[2]; + _resolvedIP[3] = resolvedIP[3]; + downcaseAndRemoveWwwPrefix(_domainName); + return _udp.begin(_port) == 1; +} + +void DNSServer::setErrorReplyCode(const DNSReplyCode &replyCode) +{ + _errorReplyCode = replyCode; +} + +void DNSServer::setTTL(const uint32_t &ttl) +{ + _ttl = htonl(ttl); +} + +void DNSServer::stop() +{ + _udp.stop(); +} + +void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName) +{ + domainName.toLowerCase(); + domainName.replace("www.", ""); + domainName.replace("https://", ""); +} + +void DNSServer::processNextRequest() +{ + _currentPacketSize = _udp.parsePacket(); + if (_currentPacketSize) + { + _buffer = (unsigned char*)malloc(_currentPacketSize * sizeof(char)); + _udp.read(_buffer, _currentPacketSize); + _dnsHeader = (DNSHeader*) _buffer; + + if (_dnsHeader->QR == DNS_QR_QUERY && + _dnsHeader->OPCode == DNS_OPCODE_QUERY && + requestIncludesOnlyOneQuestion() && + (_domainName == "*" || getDomainNameWithoutWwwPrefix() == _domainName) + ) + + { + replyWithIP(); + } + else if (_dnsHeader->QR == DNS_QR_QUERY) + { + replyWithCustomCode(); + } + + free(_buffer); + } +} + +bool DNSServer::requestIncludesOnlyOneQuestion() +{ + return ntohs(_dnsHeader->QDCount) == 1 && + _dnsHeader->ANCount == 0 && + _dnsHeader->NSCount == 0 && + _dnsHeader->ARCount == 0; +} + +String DNSServer::getDomainNameWithoutWwwPrefix() +{ + String parsedDomainName = ""; + unsigned char *start = _buffer + 12; + if (*start == 0) + { + return parsedDomainName; + } + int pos = 0; + while(true) + { + unsigned char labelLength = *(start + pos); + for(int i = 0; i < labelLength; i++) + { + pos++; + parsedDomainName += (char)*(start + pos); + } + pos++; + if (*(start + pos) == 0) + { + downcaseAndRemoveWwwPrefix(parsedDomainName); + return parsedDomainName; + } + else + { + parsedDomainName += "."; + } + } +} + +void DNSServer::replyWithIP() +{ + _dnsHeader->QR = DNS_QR_RESPONSE; + _dnsHeader->ANCount = _dnsHeader->QDCount; + _dnsHeader->QDCount = _dnsHeader->QDCount; + //_dnsHeader->RA = 1; + + _udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); + _udp.write(_buffer, _currentPacketSize); + + _udp.write((uint8_t)192); // answer name is a pointer + _udp.write((uint8_t)12); // pointer to offset at 0x00c + + _udp.write((uint8_t)0); // 0x0001 answer is type A query (host address) + _udp.write((uint8_t)1); + + _udp.write((uint8_t)0); //0x0001 answer is class IN (internet address) + _udp.write((uint8_t)1); + + _udp.write((unsigned char*)&_ttl, 4); + + // Length of RData is 4 bytes (because, in this case, RData is IPv4) + _udp.write((uint8_t)0); + _udp.write((uint8_t)4); + _udp.write(_resolvedIP, sizeof(_resolvedIP)); + _udp.endPacket(); + + + + #ifdef DEBUG + DEBUG_OUTPUT.print("DNS responds: "); + DEBUG_OUTPUT.print(_resolvedIP[0]); + DEBUG_OUTPUT.print("."); + DEBUG_OUTPUT.print(_resolvedIP[1]); + DEBUG_OUTPUT.print("."); + DEBUG_OUTPUT.print(_resolvedIP[2]); + DEBUG_OUTPUT.print("."); + DEBUG_OUTPUT.print(_resolvedIP[3]); + DEBUG_OUTPUT.print(" for "); + DEBUG_OUTPUT.println(getDomainNameWithoutWwwPrefix()); + #endif +} + +void DNSServer::replyWithCustomCode() +{ + _dnsHeader->QR = DNS_QR_RESPONSE; + _dnsHeader->RCode = (unsigned char)_errorReplyCode; + _dnsHeader->QDCount = 0; + + _udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); + _udp.write(_buffer, sizeof(DNSHeader)); + _udp.endPacket(); +} diff --git a/works/Aram Bartholl/fossils of late capitalism/otastaImg/DNSServer.h b/works/Aram Bartholl/fossils of late capitalism/otastaImg/DNSServer.h new file mode 100755 index 0000000..2bade4b --- /dev/null +++ b/works/Aram Bartholl/fossils of late capitalism/otastaImg/DNSServer.h @@ -0,0 +1,72 @@ +#ifndef DNSServer_h +#define DNSServer_h +#include + +#define DNS_QR_QUERY 0 +#define DNS_QR_RESPONSE 1 +#define DNS_OPCODE_QUERY 0 + +enum class DNSReplyCode +{ + NoError = 0, + FormError = 1, + ServerFailure = 2, + NonExistentDomain = 3, + NotImplemented = 4, + Refused = 5, + YXDomain = 6, + YXRRSet = 7, + NXRRSet = 8 +}; + +struct DNSHeader +{ + uint16_t ID; // identification number + unsigned char RD : 1; // recursion desired + unsigned char TC : 1; // truncated message + unsigned char AA : 1; // authoritive answer + unsigned char OPCode : 4; // message_type + unsigned char QR : 1; // query/response flag + unsigned char RCode : 4; // response code + unsigned char Z : 3; // its z! reserved + unsigned char RA : 1; // recursion available + uint16_t QDCount; // number of question entries + uint16_t ANCount; // number of answer entries + uint16_t NSCount; // number of authority entries + uint16_t ARCount; // number of resource entries +}; + +class DNSServer +{ + public: + DNSServer(); + void processNextRequest(); + void setErrorReplyCode(const DNSReplyCode &replyCode); + void setTTL(const uint32_t &ttl); + + // Returns true if successful, false if there are no sockets available + bool start(const uint16_t &port, + const String &domainName, + const IPAddress &resolvedIP); + // stops the DNS server + void stop(); + + private: + WiFiUDP _udp; + uint16_t _port; + String _domainName; + unsigned char _resolvedIP[4]; + int _currentPacketSize; + unsigned char* _buffer; + DNSHeader* _dnsHeader; + uint32_t _ttl; + DNSReplyCode _errorReplyCode; + + void downcaseAndRemoveWwwPrefix(String &domainName); + String getDomainNameWithoutWwwPrefix(); + bool requestIncludesOnlyOneQuestion(); + void replyWithIP(); + void replyWithCustomCode(); +}; +#endif + diff --git a/works/Aram Bartholl/fossils of late capitalism/otastaImg/data/.DS_Store b/works/Aram Bartholl/fossils of late capitalism/otastaImg/data/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..4df10455818990b6836e6fee6943ca41cd359724 GIT binary patch literal 6148 zcmeHKOHRWu5FNJ>Dq_<`7c4Eo1$qG#s`LP;2cVRo0!m1vw)-4}4L5)*a1}1V5qL8; zQJvIchY*^n?B~qKW52j|Ohjh3%cn$RA{wDE4vtYB5Vmva$-rwk*hn8++7#>Q;^t>p}ubdV>vni?^{tQOlbA>@u?2Y&rWrifRM3vr znB`M2M|#2kC$vZM27N^G2R^|#=#|Hzq6{bl$^h>qoWgui==pM&>{?Ft0|1e0OlmTVnUol{kY>~|{C4aW|CdX&3MOmV- ouwUb_4M9VWV)*h=e2O9hz2ycl_1HLs2BIGVLW5Syz^^j!1rE%04gdfE literal 0 HcmV?d00001 diff --git a/works/Aram Bartholl/fossils of late capitalism/fossilsoflatecapitalism.gif b/works/Aram Bartholl/fossils of late capitalism/otastaImg/data/fossilsoflatecapitalism.gif similarity index 100% rename from works/Aram Bartholl/fossils of late capitalism/fossilsoflatecapitalism.gif rename to works/Aram Bartholl/fossils of late capitalism/otastaImg/data/fossilsoflatecapitalism.gif diff --git a/works/Aram Bartholl/fossils of late capitalism/otastaImg/data/index.html b/works/Aram Bartholl/fossils of late capitalism/otastaImg/data/index.html new file mode 100644 index 0000000..14e1e6d --- /dev/null +++ b/works/Aram Bartholl/fossils of late capitalism/otastaImg/data/index.html @@ -0,0 +1,16 @@ + + + + + Fossils of late capitalism + + + + + +
+ +
+ + + \ No newline at end of file diff --git a/works/Aram Bartholl/fossils of late capitalism/otastaImg/otastaImg.ino b/works/Aram Bartholl/fossils of late capitalism/otastaImg/otastaImg.ino new file mode 100644 index 0000000..b786dc5 --- /dev/null +++ b/works/Aram Bartholl/fossils of late capitalism/otastaImg/otastaImg.ino @@ -0,0 +1,98 @@ + // Captive portal with (arduino) OTA + SPIFFS + + #include + #include + #include + #include + #include // Over-the-Air updates + #include + #include "./DNSServer.h" // Dns server + #include // SPIFFS + + DNSServer dnsServer; + const byte DNS_PORT = 53; + + ESP8266WebServer server(80); + + #ifndef STASSID + #define STASSID "\xF0\x9F\x9B\xB4 UNFLASHED" + //#define STASPSK "mypassword" + #endif + + IPAddress apIP(192, 168, 4, 1); + const char* ssid = STASSID; + //const char* password = STAPSK; + + void setup() { + Serial.begin(115200); + Serial.println("Booting"); + + WiFi.mode(WIFI_AP); + WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); + WiFi.softAP(ssid); + dnsServer.start(DNS_PORT, "*", apIP); // redirect dns request to AP ip + + MDNS.begin("esp8266", WiFi.softAPIP()); + Serial.println("Ready"); + Serial.print("IP address: "); + Serial.println(WiFi.softAPIP()); + + //Over-the-Air updates + ArduinoOTA.setHostname("ESP8266"); + //ArduinoOTA.setPassword("change-me"); //disabled to allow data uploads + ArduinoOTA.begin(); + SPIFFS.begin(); + + //redirect all traffic to index.html + server.onNotFound([]() { + if(!handleFileRead(server.uri())){ + const char *metaRefreshStr = "

redirecting...

"; + server.send(200, "text/html", metaRefreshStr); + } + }); + + server.begin(); + + } + + void loop() { + dnsServer.processNextRequest(); + ArduinoOTA.handle(); + server.handleClient(); + delay(50); + } + + +String getContentType(String filename){ + if(server.hasArg("download")) return "application/octet-stream"; + else if(filename.endsWith(".htm")) return "text/html"; + else if(filename.endsWith(".html")) return "text/html"; + else if(filename.endsWith(".css")) return "text/css"; + else if(filename.endsWith(".js")) return "application/javascript"; + else if(filename.endsWith(".png")) return "image/png"; + else if(filename.endsWith(".gif")) return "image/gif"; + else if(filename.endsWith(".jpg")) return "image/jpeg"; + else if(filename.endsWith(".ico")) return "image/x-icon"; + else if(filename.endsWith(".xml")) return "text/xml"; + else if(filename.endsWith(".mp4")) return "video/mp4"; + else if(filename.endsWith(".pdf")) return "application/x-pdf"; + else if(filename.endsWith(".zip")) return "application/x-zip"; + else if(filename.endsWith(".gz")) return "application/x-gzip"; + return "text/plain"; +} + +//Given a file path, look for it in the SPIFFS file storage. Returns true if found, returns false if not found. +bool handleFileRead(String path){ + if(path.endsWith("/")) path += "index.html"; + String contentType = getContentType(path); + String pathWithGz = path + ".gz"; + if(SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)){ + if(SPIFFS.exists(pathWithGz)) + path += ".gz"; + File file = SPIFFS.open(path, "r"); + size_t sent = server.streamFile(file, contentType); + file.close(); + return true; + } + return false; +} diff --git a/works/JODI/.DS_Store b/works/JODI/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 +#include + +#define DEBUG +#define DEBUG_OUTPUT Serial + +DNSServer::DNSServer() +{ + _ttl = htonl(60); + _errorReplyCode = DNSReplyCode::NonExistentDomain; +} + +bool DNSServer::start(const uint16_t &port, const String &domainName, + const IPAddress &resolvedIP) +{ + _port = port; + _domainName = domainName; + _resolvedIP[0] = resolvedIP[0]; + _resolvedIP[1] = resolvedIP[1]; + _resolvedIP[2] = resolvedIP[2]; + _resolvedIP[3] = resolvedIP[3]; + downcaseAndRemoveWwwPrefix(_domainName); + return _udp.begin(_port) == 1; +} + +void DNSServer::setErrorReplyCode(const DNSReplyCode &replyCode) +{ + _errorReplyCode = replyCode; +} + +void DNSServer::setTTL(const uint32_t &ttl) +{ + _ttl = htonl(ttl); +} + +void DNSServer::stop() +{ + _udp.stop(); +} + +void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName) +{ + domainName.toLowerCase(); + domainName.replace("www.", ""); + domainName.replace("https://", ""); +} + +void DNSServer::processNextRequest() +{ + _currentPacketSize = _udp.parsePacket(); + if (_currentPacketSize) + { + _buffer = (unsigned char*)malloc(_currentPacketSize * sizeof(char)); + _udp.read(_buffer, _currentPacketSize); + _dnsHeader = (DNSHeader*) _buffer; + + if (_dnsHeader->QR == DNS_QR_QUERY && + _dnsHeader->OPCode == DNS_OPCODE_QUERY && + requestIncludesOnlyOneQuestion() && + (_domainName == "*" || getDomainNameWithoutWwwPrefix() == _domainName) + ) + + { + replyWithIP(); + } + else if (_dnsHeader->QR == DNS_QR_QUERY) + { + replyWithCustomCode(); + } + + free(_buffer); + } +} + +bool DNSServer::requestIncludesOnlyOneQuestion() +{ + return ntohs(_dnsHeader->QDCount) == 1 && + _dnsHeader->ANCount == 0 && + _dnsHeader->NSCount == 0 && + _dnsHeader->ARCount == 0; +} + +String DNSServer::getDomainNameWithoutWwwPrefix() +{ + String parsedDomainName = ""; + unsigned char *start = _buffer + 12; + if (*start == 0) + { + return parsedDomainName; + } + int pos = 0; + while(true) + { + unsigned char labelLength = *(start + pos); + for(int i = 0; i < labelLength; i++) + { + pos++; + parsedDomainName += (char)*(start + pos); + } + pos++; + if (*(start + pos) == 0) + { + downcaseAndRemoveWwwPrefix(parsedDomainName); + return parsedDomainName; + } + else + { + parsedDomainName += "."; + } + } +} + +void DNSServer::replyWithIP() +{ + _dnsHeader->QR = DNS_QR_RESPONSE; + _dnsHeader->ANCount = _dnsHeader->QDCount; + _dnsHeader->QDCount = _dnsHeader->QDCount; + //_dnsHeader->RA = 1; + + _udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); + _udp.write(_buffer, _currentPacketSize); + + _udp.write((uint8_t)192); // answer name is a pointer + _udp.write((uint8_t)12); // pointer to offset at 0x00c + + _udp.write((uint8_t)0); // 0x0001 answer is type A query (host address) + _udp.write((uint8_t)1); + + _udp.write((uint8_t)0); //0x0001 answer is class IN (internet address) + _udp.write((uint8_t)1); + + _udp.write((unsigned char*)&_ttl, 4); + + // Length of RData is 4 bytes (because, in this case, RData is IPv4) + _udp.write((uint8_t)0); + _udp.write((uint8_t)4); + _udp.write(_resolvedIP, sizeof(_resolvedIP)); + _udp.endPacket(); + + + + #ifdef DEBUG + DEBUG_OUTPUT.print("DNS responds: "); + DEBUG_OUTPUT.print(_resolvedIP[0]); + DEBUG_OUTPUT.print("."); + DEBUG_OUTPUT.print(_resolvedIP[1]); + DEBUG_OUTPUT.print("."); + DEBUG_OUTPUT.print(_resolvedIP[2]); + DEBUG_OUTPUT.print("."); + DEBUG_OUTPUT.print(_resolvedIP[3]); + DEBUG_OUTPUT.print(" for "); + DEBUG_OUTPUT.println(getDomainNameWithoutWwwPrefix()); + #endif +} + +void DNSServer::replyWithCustomCode() +{ + _dnsHeader->QR = DNS_QR_RESPONSE; + _dnsHeader->RCode = (unsigned char)_errorReplyCode; + _dnsHeader->QDCount = 0; + + _udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); + _udp.write(_buffer, sizeof(DNSHeader)); + _udp.endPacket(); +} diff --git a/works/JODI/otastaImg/DNSServer.h b/works/JODI/otastaImg/DNSServer.h new file mode 100755 index 0000000..2bade4b --- /dev/null +++ b/works/JODI/otastaImg/DNSServer.h @@ -0,0 +1,72 @@ +#ifndef DNSServer_h +#define DNSServer_h +#include + +#define DNS_QR_QUERY 0 +#define DNS_QR_RESPONSE 1 +#define DNS_OPCODE_QUERY 0 + +enum class DNSReplyCode +{ + NoError = 0, + FormError = 1, + ServerFailure = 2, + NonExistentDomain = 3, + NotImplemented = 4, + Refused = 5, + YXDomain = 6, + YXRRSet = 7, + NXRRSet = 8 +}; + +struct DNSHeader +{ + uint16_t ID; // identification number + unsigned char RD : 1; // recursion desired + unsigned char TC : 1; // truncated message + unsigned char AA : 1; // authoritive answer + unsigned char OPCode : 4; // message_type + unsigned char QR : 1; // query/response flag + unsigned char RCode : 4; // response code + unsigned char Z : 3; // its z! reserved + unsigned char RA : 1; // recursion available + uint16_t QDCount; // number of question entries + uint16_t ANCount; // number of answer entries + uint16_t NSCount; // number of authority entries + uint16_t ARCount; // number of resource entries +}; + +class DNSServer +{ + public: + DNSServer(); + void processNextRequest(); + void setErrorReplyCode(const DNSReplyCode &replyCode); + void setTTL(const uint32_t &ttl); + + // Returns true if successful, false if there are no sockets available + bool start(const uint16_t &port, + const String &domainName, + const IPAddress &resolvedIP); + // stops the DNS server + void stop(); + + private: + WiFiUDP _udp; + uint16_t _port; + String _domainName; + unsigned char _resolvedIP[4]; + int _currentPacketSize; + unsigned char* _buffer; + DNSHeader* _dnsHeader; + uint32_t _ttl; + DNSReplyCode _errorReplyCode; + + void downcaseAndRemoveWwwPrefix(String &domainName); + String getDomainNameWithoutWwwPrefix(); + bool requestIncludesOnlyOneQuestion(); + void replyWithIP(); + void replyWithCustomCode(); +}; +#endif + diff --git a/works/JODI/otastaImg/data/.DS_Store b/works/JODI/otastaImg/data/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..4df10455818990b6836e6fee6943ca41cd359724 GIT binary patch literal 6148 zcmeHKOHRWu5FNJ>Dq_<`7c4Eo1$qG#s`LP;2cVRo0!m1vw)-4}4L5)*a1}1V5qL8; zQJvIchY*^n?B~qKW52j|Ohjh3%cn$RA{wDE4vtYB5Vmva$-rwk*hn8++7#>Q;^t>p}ubdV>vni?^{tQOlbA>@u?2Y&rWrifRM3vr znB`M2M|#2kC$vZM27N^G2R^|#=#|Hzq6{bl$^h>qoWgui==pM&>{?Ft0|1e0OlmTVnUol{kY>~|{C4aW|CdX&3MOmV- ouwUb_4M9VWV)*h=e2O9hz2ycl_1HLs2BIGVLW5Syz^^j!1rE%04gdfE literal 0 HcmV?d00001 diff --git a/works/JODI/coilww.html b/works/JODI/otastaImg/data/index.html similarity index 100% rename from works/JODI/coilww.html rename to works/JODI/otastaImg/data/index.html diff --git a/works/JODI/otastaImg/otastaImg.ino b/works/JODI/otastaImg/otastaImg.ino new file mode 100644 index 0000000..b786dc5 --- /dev/null +++ b/works/JODI/otastaImg/otastaImg.ino @@ -0,0 +1,98 @@ + // Captive portal with (arduino) OTA + SPIFFS + + #include + #include + #include + #include + #include // Over-the-Air updates + #include + #include "./DNSServer.h" // Dns server + #include // SPIFFS + + DNSServer dnsServer; + const byte DNS_PORT = 53; + + ESP8266WebServer server(80); + + #ifndef STASSID + #define STASSID "\xF0\x9F\x9B\xB4 UNFLASHED" + //#define STASPSK "mypassword" + #endif + + IPAddress apIP(192, 168, 4, 1); + const char* ssid = STASSID; + //const char* password = STAPSK; + + void setup() { + Serial.begin(115200); + Serial.println("Booting"); + + WiFi.mode(WIFI_AP); + WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); + WiFi.softAP(ssid); + dnsServer.start(DNS_PORT, "*", apIP); // redirect dns request to AP ip + + MDNS.begin("esp8266", WiFi.softAPIP()); + Serial.println("Ready"); + Serial.print("IP address: "); + Serial.println(WiFi.softAPIP()); + + //Over-the-Air updates + ArduinoOTA.setHostname("ESP8266"); + //ArduinoOTA.setPassword("change-me"); //disabled to allow data uploads + ArduinoOTA.begin(); + SPIFFS.begin(); + + //redirect all traffic to index.html + server.onNotFound([]() { + if(!handleFileRead(server.uri())){ + const char *metaRefreshStr = "

redirecting...

"; + server.send(200, "text/html", metaRefreshStr); + } + }); + + server.begin(); + + } + + void loop() { + dnsServer.processNextRequest(); + ArduinoOTA.handle(); + server.handleClient(); + delay(50); + } + + +String getContentType(String filename){ + if(server.hasArg("download")) return "application/octet-stream"; + else if(filename.endsWith(".htm")) return "text/html"; + else if(filename.endsWith(".html")) return "text/html"; + else if(filename.endsWith(".css")) return "text/css"; + else if(filename.endsWith(".js")) return "application/javascript"; + else if(filename.endsWith(".png")) return "image/png"; + else if(filename.endsWith(".gif")) return "image/gif"; + else if(filename.endsWith(".jpg")) return "image/jpeg"; + else if(filename.endsWith(".ico")) return "image/x-icon"; + else if(filename.endsWith(".xml")) return "text/xml"; + else if(filename.endsWith(".mp4")) return "video/mp4"; + else if(filename.endsWith(".pdf")) return "application/x-pdf"; + else if(filename.endsWith(".zip")) return "application/x-zip"; + else if(filename.endsWith(".gz")) return "application/x-gzip"; + return "text/plain"; +} + +//Given a file path, look for it in the SPIFFS file storage. Returns true if found, returns false if not found. +bool handleFileRead(String path){ + if(path.endsWith("/")) path += "index.html"; + String contentType = getContentType(path); + String pathWithGz = path + ".gz"; + if(SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)){ + if(SPIFFS.exists(pathWithGz)) + path += ".gz"; + File file = SPIFFS.open(path, "r"); + size_t sent = server.streamFile(file, contentType); + file.close(); + return true; + } + return false; +} diff --git a/works/Jonas Lund/.DS_Store b/works/Jonas Lund/.DS_Store index 85904a6a71e31b1396d4b8fd2736cc67b9c0e282..b876b1f1f9098f1ca4fb610f7c04412ae1a21536 100644 GIT binary patch delta 76 zcmZoMXffDe%gD^Yz%bc?Q9~dpCqD_u=J1IAc|KvzAxEH~nox=h7GagiXBc@mKVwv6 No7lj*nVsV=KLBPJ7)Ag9 delta 65 zcmZoMXffDe%gD^c6*Sp_QG+X`v?Q5<;r7}mCnwu6YVf7FAOsi~CU0OgWMVSd{E$(N NZDIr4W_FIh`~b9U6^8%- diff --git a/works/Jonas Lund/hello capitalism/.DS_Store b/works/Jonas Lund/hello capitalism/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 +#include + +#define DEBUG +#define DEBUG_OUTPUT Serial + +DNSServer::DNSServer() +{ + _ttl = htonl(60); + _errorReplyCode = DNSReplyCode::NonExistentDomain; +} + +bool DNSServer::start(const uint16_t &port, const String &domainName, + const IPAddress &resolvedIP) +{ + _port = port; + _domainName = domainName; + _resolvedIP[0] = resolvedIP[0]; + _resolvedIP[1] = resolvedIP[1]; + _resolvedIP[2] = resolvedIP[2]; + _resolvedIP[3] = resolvedIP[3]; + downcaseAndRemoveWwwPrefix(_domainName); + return _udp.begin(_port) == 1; +} + +void DNSServer::setErrorReplyCode(const DNSReplyCode &replyCode) +{ + _errorReplyCode = replyCode; +} + +void DNSServer::setTTL(const uint32_t &ttl) +{ + _ttl = htonl(ttl); +} + +void DNSServer::stop() +{ + _udp.stop(); +} + +void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName) +{ + domainName.toLowerCase(); + domainName.replace("www.", ""); + domainName.replace("https://", ""); +} + +void DNSServer::processNextRequest() +{ + _currentPacketSize = _udp.parsePacket(); + if (_currentPacketSize) + { + _buffer = (unsigned char*)malloc(_currentPacketSize * sizeof(char)); + _udp.read(_buffer, _currentPacketSize); + _dnsHeader = (DNSHeader*) _buffer; + + if (_dnsHeader->QR == DNS_QR_QUERY && + _dnsHeader->OPCode == DNS_OPCODE_QUERY && + requestIncludesOnlyOneQuestion() && + (_domainName == "*" || getDomainNameWithoutWwwPrefix() == _domainName) + ) + + { + replyWithIP(); + } + else if (_dnsHeader->QR == DNS_QR_QUERY) + { + replyWithCustomCode(); + } + + free(_buffer); + } +} + +bool DNSServer::requestIncludesOnlyOneQuestion() +{ + return ntohs(_dnsHeader->QDCount) == 1 && + _dnsHeader->ANCount == 0 && + _dnsHeader->NSCount == 0 && + _dnsHeader->ARCount == 0; +} + +String DNSServer::getDomainNameWithoutWwwPrefix() +{ + String parsedDomainName = ""; + unsigned char *start = _buffer + 12; + if (*start == 0) + { + return parsedDomainName; + } + int pos = 0; + while(true) + { + unsigned char labelLength = *(start + pos); + for(int i = 0; i < labelLength; i++) + { + pos++; + parsedDomainName += (char)*(start + pos); + } + pos++; + if (*(start + pos) == 0) + { + downcaseAndRemoveWwwPrefix(parsedDomainName); + return parsedDomainName; + } + else + { + parsedDomainName += "."; + } + } +} + +void DNSServer::replyWithIP() +{ + _dnsHeader->QR = DNS_QR_RESPONSE; + _dnsHeader->ANCount = _dnsHeader->QDCount; + _dnsHeader->QDCount = _dnsHeader->QDCount; + //_dnsHeader->RA = 1; + + _udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); + _udp.write(_buffer, _currentPacketSize); + + _udp.write((uint8_t)192); // answer name is a pointer + _udp.write((uint8_t)12); // pointer to offset at 0x00c + + _udp.write((uint8_t)0); // 0x0001 answer is type A query (host address) + _udp.write((uint8_t)1); + + _udp.write((uint8_t)0); //0x0001 answer is class IN (internet address) + _udp.write((uint8_t)1); + + _udp.write((unsigned char*)&_ttl, 4); + + // Length of RData is 4 bytes (because, in this case, RData is IPv4) + _udp.write((uint8_t)0); + _udp.write((uint8_t)4); + _udp.write(_resolvedIP, sizeof(_resolvedIP)); + _udp.endPacket(); + + + + #ifdef DEBUG + DEBUG_OUTPUT.print("DNS responds: "); + DEBUG_OUTPUT.print(_resolvedIP[0]); + DEBUG_OUTPUT.print("."); + DEBUG_OUTPUT.print(_resolvedIP[1]); + DEBUG_OUTPUT.print("."); + DEBUG_OUTPUT.print(_resolvedIP[2]); + DEBUG_OUTPUT.print("."); + DEBUG_OUTPUT.print(_resolvedIP[3]); + DEBUG_OUTPUT.print(" for "); + DEBUG_OUTPUT.println(getDomainNameWithoutWwwPrefix()); + #endif +} + +void DNSServer::replyWithCustomCode() +{ + _dnsHeader->QR = DNS_QR_RESPONSE; + _dnsHeader->RCode = (unsigned char)_errorReplyCode; + _dnsHeader->QDCount = 0; + + _udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); + _udp.write(_buffer, sizeof(DNSHeader)); + _udp.endPacket(); +} diff --git a/works/Jonas Lund/hello capitalism/otastaImg/DNSServer.h b/works/Jonas Lund/hello capitalism/otastaImg/DNSServer.h new file mode 100755 index 0000000..2bade4b --- /dev/null +++ b/works/Jonas Lund/hello capitalism/otastaImg/DNSServer.h @@ -0,0 +1,72 @@ +#ifndef DNSServer_h +#define DNSServer_h +#include + +#define DNS_QR_QUERY 0 +#define DNS_QR_RESPONSE 1 +#define DNS_OPCODE_QUERY 0 + +enum class DNSReplyCode +{ + NoError = 0, + FormError = 1, + ServerFailure = 2, + NonExistentDomain = 3, + NotImplemented = 4, + Refused = 5, + YXDomain = 6, + YXRRSet = 7, + NXRRSet = 8 +}; + +struct DNSHeader +{ + uint16_t ID; // identification number + unsigned char RD : 1; // recursion desired + unsigned char TC : 1; // truncated message + unsigned char AA : 1; // authoritive answer + unsigned char OPCode : 4; // message_type + unsigned char QR : 1; // query/response flag + unsigned char RCode : 4; // response code + unsigned char Z : 3; // its z! reserved + unsigned char RA : 1; // recursion available + uint16_t QDCount; // number of question entries + uint16_t ANCount; // number of answer entries + uint16_t NSCount; // number of authority entries + uint16_t ARCount; // number of resource entries +}; + +class DNSServer +{ + public: + DNSServer(); + void processNextRequest(); + void setErrorReplyCode(const DNSReplyCode &replyCode); + void setTTL(const uint32_t &ttl); + + // Returns true if successful, false if there are no sockets available + bool start(const uint16_t &port, + const String &domainName, + const IPAddress &resolvedIP); + // stops the DNS server + void stop(); + + private: + WiFiUDP _udp; + uint16_t _port; + String _domainName; + unsigned char _resolvedIP[4]; + int _currentPacketSize; + unsigned char* _buffer; + DNSHeader* _dnsHeader; + uint32_t _ttl; + DNSReplyCode _errorReplyCode; + + void downcaseAndRemoveWwwPrefix(String &domainName); + String getDomainNameWithoutWwwPrefix(); + bool requestIncludesOnlyOneQuestion(); + void replyWithIP(); + void replyWithCustomCode(); +}; +#endif + diff --git a/works/Jonas Lund/hello capitalism/otastaImg/data/.DS_Store b/works/Jonas Lund/hello capitalism/otastaImg/data/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..4df10455818990b6836e6fee6943ca41cd359724 GIT binary patch literal 6148 zcmeHKOHRWu5FNJ>Dq_<`7c4Eo1$qG#s`LP;2cVRo0!m1vw)-4}4L5)*a1}1V5qL8; zQJvIchY*^n?B~qKW52j|Ohjh3%cn$RA{wDE4vtYB5Vmva$-rwk*hn8++7#>Q;^t>p}ubdV>vni?^{tQOlbA>@u?2Y&rWrifRM3vr znB`M2M|#2kC$vZM27N^G2R^|#=#|Hzq6{bl$^h>qoWgui==pM&>{?Ft0|1e0OlmTVnUol{kY>~|{C4aW|CdX&3MOmV- ouwUb_4M9VWV)*h=e2O9hz2ycl_1HLs2BIGVLW5Syz^^j!1rE%04gdfE literal 0 HcmV?d00001 diff --git a/works/Jonas Lund/hello capitalism/index.html b/works/Jonas Lund/hello capitalism/otastaImg/data/index.html similarity index 100% rename from works/Jonas Lund/hello capitalism/index.html rename to works/Jonas Lund/hello capitalism/otastaImg/data/index.html diff --git a/works/Jonas Lund/hello capitalism/jquery.js b/works/Jonas Lund/hello capitalism/otastaImg/data/jquery.js similarity index 100% rename from works/Jonas Lund/hello capitalism/jquery.js rename to works/Jonas Lund/hello capitalism/otastaImg/data/jquery.js diff --git a/works/Jonas Lund/hello capitalism/script_type-retype.js b/works/Jonas Lund/hello capitalism/otastaImg/data/script_type-retype.js similarity index 100% rename from works/Jonas Lund/hello capitalism/script_type-retype.js rename to works/Jonas Lund/hello capitalism/otastaImg/data/script_type-retype.js diff --git a/works/Jonas Lund/hello capitalism/styles-type.css b/works/Jonas Lund/hello capitalism/otastaImg/data/styles-type.css similarity index 100% rename from works/Jonas Lund/hello capitalism/styles-type.css rename to works/Jonas Lund/hello capitalism/otastaImg/data/styles-type.css diff --git a/works/Jonas Lund/hello capitalism/otastaImg/otastaImg.ino b/works/Jonas Lund/hello capitalism/otastaImg/otastaImg.ino new file mode 100644 index 0000000..b786dc5 --- /dev/null +++ b/works/Jonas Lund/hello capitalism/otastaImg/otastaImg.ino @@ -0,0 +1,98 @@ + // Captive portal with (arduino) OTA + SPIFFS + + #include + #include + #include + #include + #include // Over-the-Air updates + #include + #include "./DNSServer.h" // Dns server + #include // SPIFFS + + DNSServer dnsServer; + const byte DNS_PORT = 53; + + ESP8266WebServer server(80); + + #ifndef STASSID + #define STASSID "\xF0\x9F\x9B\xB4 UNFLASHED" + //#define STASPSK "mypassword" + #endif + + IPAddress apIP(192, 168, 4, 1); + const char* ssid = STASSID; + //const char* password = STAPSK; + + void setup() { + Serial.begin(115200); + Serial.println("Booting"); + + WiFi.mode(WIFI_AP); + WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); + WiFi.softAP(ssid); + dnsServer.start(DNS_PORT, "*", apIP); // redirect dns request to AP ip + + MDNS.begin("esp8266", WiFi.softAPIP()); + Serial.println("Ready"); + Serial.print("IP address: "); + Serial.println(WiFi.softAPIP()); + + //Over-the-Air updates + ArduinoOTA.setHostname("ESP8266"); + //ArduinoOTA.setPassword("change-me"); //disabled to allow data uploads + ArduinoOTA.begin(); + SPIFFS.begin(); + + //redirect all traffic to index.html + server.onNotFound([]() { + if(!handleFileRead(server.uri())){ + const char *metaRefreshStr = "

redirecting...

"; + server.send(200, "text/html", metaRefreshStr); + } + }); + + server.begin(); + + } + + void loop() { + dnsServer.processNextRequest(); + ArduinoOTA.handle(); + server.handleClient(); + delay(50); + } + + +String getContentType(String filename){ + if(server.hasArg("download")) return "application/octet-stream"; + else if(filename.endsWith(".htm")) return "text/html"; + else if(filename.endsWith(".html")) return "text/html"; + else if(filename.endsWith(".css")) return "text/css"; + else if(filename.endsWith(".js")) return "application/javascript"; + else if(filename.endsWith(".png")) return "image/png"; + else if(filename.endsWith(".gif")) return "image/gif"; + else if(filename.endsWith(".jpg")) return "image/jpeg"; + else if(filename.endsWith(".ico")) return "image/x-icon"; + else if(filename.endsWith(".xml")) return "text/xml"; + else if(filename.endsWith(".mp4")) return "video/mp4"; + else if(filename.endsWith(".pdf")) return "application/x-pdf"; + else if(filename.endsWith(".zip")) return "application/x-zip"; + else if(filename.endsWith(".gz")) return "application/x-gzip"; + return "text/plain"; +} + +//Given a file path, look for it in the SPIFFS file storage. Returns true if found, returns false if not found. +bool handleFileRead(String path){ + if(path.endsWith("/")) path += "index.html"; + String contentType = getContentType(path); + String pathWithGz = path + ".gz"; + if(SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)){ + if(SPIFFS.exists(pathWithGz)) + path += ".gz"; + File file = SPIFFS.open(path, "r"); + size_t sent = server.streamFile(file, contentType); + file.close(); + return true; + } + return false; +} diff --git a/works/Martin Howse/.DS_Store b/works/Martin Howse/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 - - - - URL - https://github.com/microresearch/notes/tree/master/scooter/arduino/wokthecables - - diff --git a/works/Martin Howse/wokthecables/.DS_Store b/works/Martin Howse/wokthecables/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 +#include + +#define DEBUG +#define DEBUG_OUTPUT Serial + +DNSServer::DNSServer() +{ + _ttl = htonl(60); + _errorReplyCode = DNSReplyCode::NonExistentDomain; +} + +bool DNSServer::start(const uint16_t &port, const String &domainName, + const IPAddress &resolvedIP) +{ + _port = port; + _domainName = domainName; + _resolvedIP[0] = resolvedIP[0]; + _resolvedIP[1] = resolvedIP[1]; + _resolvedIP[2] = resolvedIP[2]; + _resolvedIP[3] = resolvedIP[3]; + downcaseAndRemoveWwwPrefix(_domainName); + return _udp.begin(_port) == 1; +} + +void DNSServer::setErrorReplyCode(const DNSReplyCode &replyCode) +{ + _errorReplyCode = replyCode; +} + +void DNSServer::setTTL(const uint32_t &ttl) +{ + _ttl = htonl(ttl); +} + +void DNSServer::stop() +{ + _udp.stop(); +} + +void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName) +{ + domainName.toLowerCase(); + domainName.replace("www.", ""); + domainName.replace("https://", ""); +} + +void DNSServer::processNextRequest() +{ + _currentPacketSize = _udp.parsePacket(); + if (_currentPacketSize) + { + _buffer = (unsigned char*)malloc(_currentPacketSize * sizeof(char)); + _udp.read(_buffer, _currentPacketSize); + _dnsHeader = (DNSHeader*) _buffer; + + if (_dnsHeader->QR == DNS_QR_QUERY && + _dnsHeader->OPCode == DNS_OPCODE_QUERY && + requestIncludesOnlyOneQuestion() && + (_domainName == "*" || getDomainNameWithoutWwwPrefix() == _domainName) + ) + + { + replyWithIP(); + } + else if (_dnsHeader->QR == DNS_QR_QUERY) + { + replyWithCustomCode(); + } + + free(_buffer); + } +} + +bool DNSServer::requestIncludesOnlyOneQuestion() +{ + return ntohs(_dnsHeader->QDCount) == 1 && + _dnsHeader->ANCount == 0 && + _dnsHeader->NSCount == 0 && + _dnsHeader->ARCount == 0; +} + +String DNSServer::getDomainNameWithoutWwwPrefix() +{ + String parsedDomainName = ""; + unsigned char *start = _buffer + 12; + if (*start == 0) + { + return parsedDomainName; + } + int pos = 0; + while(true) + { + unsigned char labelLength = *(start + pos); + for(int i = 0; i < labelLength; i++) + { + pos++; + parsedDomainName += (char)*(start + pos); + } + pos++; + if (*(start + pos) == 0) + { + downcaseAndRemoveWwwPrefix(parsedDomainName); + return parsedDomainName; + } + else + { + parsedDomainName += "."; + } + } +} + +void DNSServer::replyWithIP() +{ + _dnsHeader->QR = DNS_QR_RESPONSE; + _dnsHeader->ANCount = _dnsHeader->QDCount; + _dnsHeader->QDCount = _dnsHeader->QDCount; + //_dnsHeader->RA = 1; + + _udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); + _udp.write(_buffer, _currentPacketSize); + + _udp.write((uint8_t)192); // answer name is a pointer + _udp.write((uint8_t)12); // pointer to offset at 0x00c + + _udp.write((uint8_t)0); // 0x0001 answer is type A query (host address) + _udp.write((uint8_t)1); + + _udp.write((uint8_t)0); //0x0001 answer is class IN (internet address) + _udp.write((uint8_t)1); + + _udp.write((unsigned char*)&_ttl, 4); + + // Length of RData is 4 bytes (because, in this case, RData is IPv4) + _udp.write((uint8_t)0); + _udp.write((uint8_t)4); + _udp.write(_resolvedIP, sizeof(_resolvedIP)); + _udp.endPacket(); + + + + #ifdef DEBUG + DEBUG_OUTPUT.print("DNS responds: "); + DEBUG_OUTPUT.print(_resolvedIP[0]); + DEBUG_OUTPUT.print("."); + DEBUG_OUTPUT.print(_resolvedIP[1]); + DEBUG_OUTPUT.print("."); + DEBUG_OUTPUT.print(_resolvedIP[2]); + DEBUG_OUTPUT.print("."); + DEBUG_OUTPUT.print(_resolvedIP[3]); + DEBUG_OUTPUT.print(" for "); + DEBUG_OUTPUT.println(getDomainNameWithoutWwwPrefix()); + #endif +} + +void DNSServer::replyWithCustomCode() +{ + _dnsHeader->QR = DNS_QR_RESPONSE; + _dnsHeader->RCode = (unsigned char)_errorReplyCode; + _dnsHeader->QDCount = 0; + + _udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); + _udp.write(_buffer, sizeof(DNSHeader)); + _udp.endPacket(); +} diff --git a/works/Martin Howse/wokthecables/DNSServer.h b/works/Martin Howse/wokthecables/DNSServer.h new file mode 100755 index 0000000..2bade4b --- /dev/null +++ b/works/Martin Howse/wokthecables/DNSServer.h @@ -0,0 +1,72 @@ +#ifndef DNSServer_h +#define DNSServer_h +#include + +#define DNS_QR_QUERY 0 +#define DNS_QR_RESPONSE 1 +#define DNS_OPCODE_QUERY 0 + +enum class DNSReplyCode +{ + NoError = 0, + FormError = 1, + ServerFailure = 2, + NonExistentDomain = 3, + NotImplemented = 4, + Refused = 5, + YXDomain = 6, + YXRRSet = 7, + NXRRSet = 8 +}; + +struct DNSHeader +{ + uint16_t ID; // identification number + unsigned char RD : 1; // recursion desired + unsigned char TC : 1; // truncated message + unsigned char AA : 1; // authoritive answer + unsigned char OPCode : 4; // message_type + unsigned char QR : 1; // query/response flag + unsigned char RCode : 4; // response code + unsigned char Z : 3; // its z! reserved + unsigned char RA : 1; // recursion available + uint16_t QDCount; // number of question entries + uint16_t ANCount; // number of answer entries + uint16_t NSCount; // number of authority entries + uint16_t ARCount; // number of resource entries +}; + +class DNSServer +{ + public: + DNSServer(); + void processNextRequest(); + void setErrorReplyCode(const DNSReplyCode &replyCode); + void setTTL(const uint32_t &ttl); + + // Returns true if successful, false if there are no sockets available + bool start(const uint16_t &port, + const String &domainName, + const IPAddress &resolvedIP); + // stops the DNS server + void stop(); + + private: + WiFiUDP _udp; + uint16_t _port; + String _domainName; + unsigned char _resolvedIP[4]; + int _currentPacketSize; + unsigned char* _buffer; + DNSHeader* _dnsHeader; + uint32_t _ttl; + DNSReplyCode _errorReplyCode; + + void downcaseAndRemoveWwwPrefix(String &domainName); + String getDomainNameWithoutWwwPrefix(); + bool requestIncludesOnlyOneQuestion(); + void replyWithIP(); + void replyWithCustomCode(); +}; +#endif + diff --git a/works/Martin Howse/wokthecables/wokthecables.ino b/works/Martin Howse/wokthecables/wokthecables.ino new file mode 100644 index 0000000..9871818 --- /dev/null +++ b/works/Martin Howse/wokthecables/wokthecables.ino @@ -0,0 +1,249 @@ +// wok the cables + +// Follow conditions and interpret instructions relayed in hotspot/ESSID tags at 10 minute intervals. +// Document all findings of divinatory art on any social media using hashtag #wokthecables. + + +#include +#include +#include +#include +#include // Over-the-Air updates +#include +#include "./DNSServer.h" // Dns server +#include // SPIFFS + +const char *final_mess[3] = {"0","0","READ&EXE#wokthecables"}; + +const char *wildcards[44] = {"WOKthescooter","andrideto", + "takeESSIDX","stepsforward=", + "ShopforLAST-", "CLose*to", + "Crawlyourskin", "BACKto", + "Buyandfollow", "a CABLEto", + "TOAST-eatair", "wire1-0sign", + "FollowtheONE", "seenJUST NOW", + "go-EXE-","UNdergroundTO", + "RemainSTAYand","struggle|with", + "SendTHISmessage","@lastMESSAGEE", + "GOTOfoundreceiver","thenTOSScoins", + "DOtlastINSTRUCT","AGAIN&comment", + "turn0/left>0right","@next Xroads", + "REVdirection","forXsteps=", + "firstleft","fromNXT_", + "doitagainAND","darklyfollow_", + "goINside","@nearest*_", + "watchsigns~for","&#shinesto", + "revealitand","showit_2_", + "climb_nearest","^^^^", + "NOWMAKE_YOUR","YOURFULL_INVENTORY", + "GAMEOVER","-return_to" +}; + +// add a modifier: 0=none, 1-number, 2=operands, 3=instruction + +char wildifmod[22]={2,1,2,2,2,0,0,2,2,0,0,0,1,1,2,2,2,2,2,2,0,2}; + +const char *cards[22] = {"aFOOL-","aMAGIC-","aWITCH-","aQUEEN-","aKING-","aAMETHYST-","aLOVERS-","aCAR-","aADJUST-","aHERMIT-","aFORTUNE-","aLUST-","aHANGED-","aDEATH-","aART-","aDEVIL-","aTOWER-","aSTAR-","aMOON-","aSUN-","aAEON-","aUNIVERS-"}; + +const char *conditions[22] = {"BEGIN","always","letME_","ifOpen","0x","if","EQU","0x","else","Nver","when","4ever","CMP","ifending","ifNOT","ifAlways","WAIT","when","ifnight","ifday","LOOP","<-"}; + +char condif[22]={1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0}; + +const char *cond_operands[22] = {"start","Want","guided","opposed","ordered","hidden","two","inmotion","==","Alone","SURplus","l0nging","changing","ending","ZERO","shad0w","BRK","sh1n1ng","reflecting","day","forever","r3turned"}; + +const char *instruction[22]={"RIDE","WANT","dream","buRy","WOK","reveal","LICK","GO","dis-ASM","stay","shop","SHOUT!","stand","leave","raise","MINE","Dstroy","SHine","refl3ct","BURN","LOOP4_","reboot"}; + +const char *inst_mods[22] = {"_2_","FROM","back","INto","IN","thru","of","of","@","-","N","N","N","0","1","both","ALL","EXE","from","over","IN","_2to"}; + +char numericmod[22]={0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,1,0}; + +const char *inst_operands[22] = {"scooter","Tur/n/ing","TREE","earth","SACRIFICE","U-Bahn","JOINING","crow","cafe","LAIR","shop","stain","COIL","mask","future","tunnel","building","water","mirror","SUN","fire","EXCEPTION"}; + +const char *cars[22] = {"$","%","\(",")","*","*","_","#",".","$","+","V","¬","\\","/","^","@","*","\(",".","~","0"}; + +DNSServer dnsServer; +const byte DNS_PORT = 53; +int taroty=6001, mess=0; + +ESP8266WebServer server(80); + +#ifndef STASSID +#define STASSID "\xF0\x9F\x9B\xB4 beta" +//#define STASPSK "mypassword" +#endif + +IPAddress apIP(192, 168, 4, 1); +const char* ssid = STASSID; +//const char* password = STAPSK; + +void setup() { + Serial.begin(115200); + Serial.println("Booting"); + + WiFi.mode(WIFI_AP); + WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); + WiFi.softAP(ssid); + dnsServer.start(DNS_PORT, "*", apIP); // redirect dns request to AP ip + + MDNS.begin("esp8266", WiFi.softAPIP()); + Serial.println("Ready"); + Serial.print("IP address: "); + Serial.println(WiFi.softAPIP()); + + //Over-the-Air updates + ArduinoOTA.setHostname("ESP8266"); + ArduinoOTA.setPassword("change-me"); + ArduinoOTA.begin(); + SPIFFS.begin(); + + //redirect all traffic to index.html + server.onNotFound([]() { + Serial.println("NOTFOUND"); + if(!handleFileRead(server.uri())){ + const char *metaRefreshStr = "

redirecting...

"; + server.send(200, "text/html", metaRefreshStr); + } + }); + + server.begin(); + + + randomSeed(RANDOM_REG32); + + +} + +void loop() { + char picked_card, inter[3]; + char fullessid[2][64]; // loop to display + + // code to generate ESSID string from cards + // run this every 10 minutes for new ESSID + + if ((taroty++) > 6000){ // test with 100 = 10 seconds so 600onemin - 6000=tenmins + taroty=0; + if ((rand()%12)==11) { + // pick wildcard with suitable modifier + picked_card=rand()%22; + strcpy(fullessid[0], cards[picked_card]); + strcat(fullessid[0], wildcards[picked_card*2]); + strcpy(fullessid[1], wildcards[(picked_card*2)+1]); + + if (wildifmod[picked_card]==1) { + sprintf(inter,"%d",(rand()%12)); + strcat(fullessid[1], inter); + } + + if (wildifmod[picked_card]==2) { + picked_card=rand()%22; + strcat(fullessid[1], inst_operands[picked_card]); + } + }////// + else { + picked_card=rand()%22; + strcpy(fullessid[0], cards[picked_card]); + + picked_card=rand()%22; + if (condif[picked_card]==1) strcat(fullessid[0], conditions[picked_card]); + + picked_card=rand()%22; + strcat(fullessid[0], cond_operands[picked_card]); + + if ((rand()%6)==2) { + picked_card=rand()%22; + strcat(fullessid[0], cars[picked_card]); + } + + picked_card=rand()%22; + strcpy(fullessid[1], instruction[picked_card]); + + picked_card=rand()%22; + if (numericmod[picked_card]==0) strcat(fullessid[1], inst_mods[picked_card]); + else { + sprintf(inter,"%d",rand()%12); + strcat(fullessid[1], inter); + } + + if ((rand()%6)==2) { + picked_card=rand()%22; + strcat(fullessid[1], cars[picked_card]); + } + + picked_card=rand()%22; + strcat(fullessid[1], inst_operands[picked_card]); + } + + // if is longer than 32 truncate + // if (strlen(fullessid)>31) fullessid[31]='\0'; + + // printf("%s \n", fullessid); + // printf("%d \n",strlen(fullessid)); // is it longer than 32 if so cut. + + // Serial.println(fullessid[0]); + // Serial.println(fullessid[1]); +} + + // loop through ESSID as my HANDY only shows 16 say characters + // so first 2 fullessids and then final mess + // WiFi.softAP(fullessid); + if ((taroty%200)==0) {// was 200 but now less for testing + if (mess>2) mess=0; + if (mess<2) { + Serial.println(fullessid[mess]); + WiFi.softAP(fullessid[mess]); + } + else { + Serial.println(final_mess[mess]); + WiFi.softAP(final_mess[mess]); + } + mess++; + } + + + + // MDNS.begin("esp8266", WiFi.softAPIP()); + // Serial.println("Ready"); + // Serial.print("IP address: "); + // Serial.println(WiFi.softAPIP()); + + + dnsServer.processNextRequest(); + ArduinoOTA.handle(); + server.handleClient(); + delay(50); +} + + +String getContentType(String filename){ + if(server.hasArg("download")) return "application/octet-stream"; + else if(filename.endsWith(".htm")) return "text/html"; + else if(filename.endsWith(".html")) return "text/html"; + else if(filename.endsWith(".css")) return "text/css"; + else if(filename.endsWith(".js")) return "application/javascript"; + else if(filename.endsWith(".png")) return "image/png"; + else if(filename.endsWith(".gif")) return "image/gif"; + else if(filename.endsWith(".jpg")) return "image/jpeg"; + else if(filename.endsWith(".ico")) return "image/x-icon"; + else if(filename.endsWith(".xml")) return "text/xml"; + else if(filename.endsWith(".mp4")) return "video/mp4"; + else if(filename.endsWith(".pdf")) return "application/x-pdf"; + else if(filename.endsWith(".zip")) return "application/x-zip"; + else if(filename.endsWith(".gz")) return "application/x-gzip"; + return "text/plain"; +} + +//Given a file path, look for it in the SPIFFS file storage. Returns true if found, returns false if not found. +bool handleFileRead(String path){ + if(path.endsWith("/")) path += "index.html"; + String contentType = getContentType(path); + String pathWithGz = path + ".gz"; + if(SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)){ + if(SPIFFS.exists(pathWithGz)) + path += ".gz"; + File file = SPIFFS.open(path, "r"); + size_t sent = server.streamFile(file, contentType); + file.close(); + return true; + } + return false; +} \ No newline at end of file diff --git a/works/Sofya Aleynikova/followers/.DS_Store b/works/Sofya Aleynikova/followers/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 +#include + +#define DEBUG +#define DEBUG_OUTPUT Serial + +DNSServer::DNSServer() +{ + _ttl = htonl(60); + _errorReplyCode = DNSReplyCode::NonExistentDomain; +} + +bool DNSServer::start(const uint16_t &port, const String &domainName, + const IPAddress &resolvedIP) +{ + _port = port; + _domainName = domainName; + _resolvedIP[0] = resolvedIP[0]; + _resolvedIP[1] = resolvedIP[1]; + _resolvedIP[2] = resolvedIP[2]; + _resolvedIP[3] = resolvedIP[3]; + downcaseAndRemoveWwwPrefix(_domainName); + return _udp.begin(_port) == 1; +} + +void DNSServer::setErrorReplyCode(const DNSReplyCode &replyCode) +{ + _errorReplyCode = replyCode; +} + +void DNSServer::setTTL(const uint32_t &ttl) +{ + _ttl = htonl(ttl); +} + +void DNSServer::stop() +{ + _udp.stop(); +} + +void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName) +{ + domainName.toLowerCase(); + domainName.replace("www.", ""); + domainName.replace("https://", ""); +} + +void DNSServer::processNextRequest() +{ + _currentPacketSize = _udp.parsePacket(); + if (_currentPacketSize) + { + _buffer = (unsigned char*)malloc(_currentPacketSize * sizeof(char)); + _udp.read(_buffer, _currentPacketSize); + _dnsHeader = (DNSHeader*) _buffer; + + if (_dnsHeader->QR == DNS_QR_QUERY && + _dnsHeader->OPCode == DNS_OPCODE_QUERY && + requestIncludesOnlyOneQuestion() && + (_domainName == "*" || getDomainNameWithoutWwwPrefix() == _domainName) + ) + + { + replyWithIP(); + } + else if (_dnsHeader->QR == DNS_QR_QUERY) + { + replyWithCustomCode(); + } + + free(_buffer); + } +} + +bool DNSServer::requestIncludesOnlyOneQuestion() +{ + return ntohs(_dnsHeader->QDCount) == 1 && + _dnsHeader->ANCount == 0 && + _dnsHeader->NSCount == 0 && + _dnsHeader->ARCount == 0; +} + +String DNSServer::getDomainNameWithoutWwwPrefix() +{ + String parsedDomainName = ""; + unsigned char *start = _buffer + 12; + if (*start == 0) + { + return parsedDomainName; + } + int pos = 0; + while(true) + { + unsigned char labelLength = *(start + pos); + for(int i = 0; i < labelLength; i++) + { + pos++; + parsedDomainName += (char)*(start + pos); + } + pos++; + if (*(start + pos) == 0) + { + downcaseAndRemoveWwwPrefix(parsedDomainName); + return parsedDomainName; + } + else + { + parsedDomainName += "."; + } + } +} + +void DNSServer::replyWithIP() +{ + _dnsHeader->QR = DNS_QR_RESPONSE; + _dnsHeader->ANCount = _dnsHeader->QDCount; + _dnsHeader->QDCount = _dnsHeader->QDCount; + //_dnsHeader->RA = 1; + + _udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); + _udp.write(_buffer, _currentPacketSize); + + _udp.write((uint8_t)192); // answer name is a pointer + _udp.write((uint8_t)12); // pointer to offset at 0x00c + + _udp.write((uint8_t)0); // 0x0001 answer is type A query (host address) + _udp.write((uint8_t)1); + + _udp.write((uint8_t)0); //0x0001 answer is class IN (internet address) + _udp.write((uint8_t)1); + + _udp.write((unsigned char*)&_ttl, 4); + + // Length of RData is 4 bytes (because, in this case, RData is IPv4) + _udp.write((uint8_t)0); + _udp.write((uint8_t)4); + _udp.write(_resolvedIP, sizeof(_resolvedIP)); + _udp.endPacket(); + + + + #ifdef DEBUG + DEBUG_OUTPUT.print("DNS responds: "); + DEBUG_OUTPUT.print(_resolvedIP[0]); + DEBUG_OUTPUT.print("."); + DEBUG_OUTPUT.print(_resolvedIP[1]); + DEBUG_OUTPUT.print("."); + DEBUG_OUTPUT.print(_resolvedIP[2]); + DEBUG_OUTPUT.print("."); + DEBUG_OUTPUT.print(_resolvedIP[3]); + DEBUG_OUTPUT.print(" for "); + DEBUG_OUTPUT.println(getDomainNameWithoutWwwPrefix()); + #endif +} + +void DNSServer::replyWithCustomCode() +{ + _dnsHeader->QR = DNS_QR_RESPONSE; + _dnsHeader->RCode = (unsigned char)_errorReplyCode; + _dnsHeader->QDCount = 0; + + _udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); + _udp.write(_buffer, sizeof(DNSHeader)); + _udp.endPacket(); +} diff --git a/works/Sofya Aleynikova/followers/otastaImg/DNSServer.h b/works/Sofya Aleynikova/followers/otastaImg/DNSServer.h new file mode 100755 index 0000000..2bade4b --- /dev/null +++ b/works/Sofya Aleynikova/followers/otastaImg/DNSServer.h @@ -0,0 +1,72 @@ +#ifndef DNSServer_h +#define DNSServer_h +#include + +#define DNS_QR_QUERY 0 +#define DNS_QR_RESPONSE 1 +#define DNS_OPCODE_QUERY 0 + +enum class DNSReplyCode +{ + NoError = 0, + FormError = 1, + ServerFailure = 2, + NonExistentDomain = 3, + NotImplemented = 4, + Refused = 5, + YXDomain = 6, + YXRRSet = 7, + NXRRSet = 8 +}; + +struct DNSHeader +{ + uint16_t ID; // identification number + unsigned char RD : 1; // recursion desired + unsigned char TC : 1; // truncated message + unsigned char AA : 1; // authoritive answer + unsigned char OPCode : 4; // message_type + unsigned char QR : 1; // query/response flag + unsigned char RCode : 4; // response code + unsigned char Z : 3; // its z! reserved + unsigned char RA : 1; // recursion available + uint16_t QDCount; // number of question entries + uint16_t ANCount; // number of answer entries + uint16_t NSCount; // number of authority entries + uint16_t ARCount; // number of resource entries +}; + +class DNSServer +{ + public: + DNSServer(); + void processNextRequest(); + void setErrorReplyCode(const DNSReplyCode &replyCode); + void setTTL(const uint32_t &ttl); + + // Returns true if successful, false if there are no sockets available + bool start(const uint16_t &port, + const String &domainName, + const IPAddress &resolvedIP); + // stops the DNS server + void stop(); + + private: + WiFiUDP _udp; + uint16_t _port; + String _domainName; + unsigned char _resolvedIP[4]; + int _currentPacketSize; + unsigned char* _buffer; + DNSHeader* _dnsHeader; + uint32_t _ttl; + DNSReplyCode _errorReplyCode; + + void downcaseAndRemoveWwwPrefix(String &domainName); + String getDomainNameWithoutWwwPrefix(); + bool requestIncludesOnlyOneQuestion(); + void replyWithIP(); + void replyWithCustomCode(); +}; +#endif + diff --git a/works/Sofya Aleynikova/followers/otastaImg/data/.DS_Store b/works/Sofya Aleynikova/followers/otastaImg/data/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..4df10455818990b6836e6fee6943ca41cd359724 GIT binary patch literal 6148 zcmeHKOHRWu5FNJ>Dq_<`7c4Eo1$qG#s`LP;2cVRo0!m1vw)-4}4L5)*a1}1V5qL8; zQJvIchY*^n?B~qKW52j|Ohjh3%cn$RA{wDE4vtYB5Vmva$-rwk*hn8++7#>Q;^t>p}ubdV>vni?^{tQOlbA>@u?2Y&rWrifRM3vr znB`M2M|#2kC$vZM27N^G2R^|#=#|Hzq6{bl$^h>qoWgui==pM&>{?Ft0|1e0OlmTVnUol{kY>~|{C4aW|CdX&3MOmV- ouwUb_4M9VWV)*h=e2O9hz2ycl_1HLs2BIGVLW5Syz^^j!1rE%04gdfE literal 0 HcmV?d00001 diff --git a/works/Sofya Aleynikova/followers/followers.gif b/works/Sofya Aleynikova/followers/otastaImg/data/followers.gif similarity index 100% rename from works/Sofya Aleynikova/followers/followers.gif rename to works/Sofya Aleynikova/followers/otastaImg/data/followers.gif diff --git a/works/Sofya Aleynikova/followers/otastaImg/data/index.html b/works/Sofya Aleynikova/followers/otastaImg/data/index.html new file mode 100644 index 0000000..fcb2be6 --- /dev/null +++ b/works/Sofya Aleynikova/followers/otastaImg/data/index.html @@ -0,0 +1,16 @@ + + + + + followers + + + + + +
+ +
+ + + \ No newline at end of file diff --git a/works/Sofya Aleynikova/followers/otastaImg/otastaImg.ino b/works/Sofya Aleynikova/followers/otastaImg/otastaImg.ino new file mode 100644 index 0000000..b786dc5 --- /dev/null +++ b/works/Sofya Aleynikova/followers/otastaImg/otastaImg.ino @@ -0,0 +1,98 @@ + // Captive portal with (arduino) OTA + SPIFFS + + #include + #include + #include + #include + #include // Over-the-Air updates + #include + #include "./DNSServer.h" // Dns server + #include // SPIFFS + + DNSServer dnsServer; + const byte DNS_PORT = 53; + + ESP8266WebServer server(80); + + #ifndef STASSID + #define STASSID "\xF0\x9F\x9B\xB4 UNFLASHED" + //#define STASPSK "mypassword" + #endif + + IPAddress apIP(192, 168, 4, 1); + const char* ssid = STASSID; + //const char* password = STAPSK; + + void setup() { + Serial.begin(115200); + Serial.println("Booting"); + + WiFi.mode(WIFI_AP); + WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); + WiFi.softAP(ssid); + dnsServer.start(DNS_PORT, "*", apIP); // redirect dns request to AP ip + + MDNS.begin("esp8266", WiFi.softAPIP()); + Serial.println("Ready"); + Serial.print("IP address: "); + Serial.println(WiFi.softAPIP()); + + //Over-the-Air updates + ArduinoOTA.setHostname("ESP8266"); + //ArduinoOTA.setPassword("change-me"); //disabled to allow data uploads + ArduinoOTA.begin(); + SPIFFS.begin(); + + //redirect all traffic to index.html + server.onNotFound([]() { + if(!handleFileRead(server.uri())){ + const char *metaRefreshStr = "

redirecting...

"; + server.send(200, "text/html", metaRefreshStr); + } + }); + + server.begin(); + + } + + void loop() { + dnsServer.processNextRequest(); + ArduinoOTA.handle(); + server.handleClient(); + delay(50); + } + + +String getContentType(String filename){ + if(server.hasArg("download")) return "application/octet-stream"; + else if(filename.endsWith(".htm")) return "text/html"; + else if(filename.endsWith(".html")) return "text/html"; + else if(filename.endsWith(".css")) return "text/css"; + else if(filename.endsWith(".js")) return "application/javascript"; + else if(filename.endsWith(".png")) return "image/png"; + else if(filename.endsWith(".gif")) return "image/gif"; + else if(filename.endsWith(".jpg")) return "image/jpeg"; + else if(filename.endsWith(".ico")) return "image/x-icon"; + else if(filename.endsWith(".xml")) return "text/xml"; + else if(filename.endsWith(".mp4")) return "video/mp4"; + else if(filename.endsWith(".pdf")) return "application/x-pdf"; + else if(filename.endsWith(".zip")) return "application/x-zip"; + else if(filename.endsWith(".gz")) return "application/x-gzip"; + return "text/plain"; +} + +//Given a file path, look for it in the SPIFFS file storage. Returns true if found, returns false if not found. +bool handleFileRead(String path){ + if(path.endsWith("/")) path += "index.html"; + String contentType = getContentType(path); + String pathWithGz = path + ".gz"; + if(SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)){ + if(SPIFFS.exists(pathWithGz)) + path += ".gz"; + File file = SPIFFS.open(path, "r"); + size_t sent = server.streamFile(file, contentType); + file.close(); + return true; + } + return false; +}