1
mirror of https://github.com/jakejarvis/jarv.is.git synced 2025-06-30 22:46:39 -04:00

v5: Revenge of the JavaScript 🦸 (#711)

Hugo ➡️ Next.js
This commit is contained in:
2021-12-30 08:18:41 -05:00
committed by GitHub
parent b7505fa260
commit 9979e1bf3f
577 changed files with 8019 additions and 11864 deletions

View File

@ -0,0 +1,157 @@
---
title: 'Bernie Sanders'' Creepy "BERN" App Wants Your Data...From Your Best Friends'
date: 2019-05-08 10:31:02-0400
description: "The team behind Bernie's campaign has a new app named BERN. It's undoubtedly a smart move, but also a concerning one for privacy advocates."
tags:
- Privacy
- Data
- Bernie Sanders
- 2020 Presidential Campaign
- Politics
image: "/static/images/notes/bernie-sanders-bern-app-data/sad-bernie.jpg"
---
The team behind Bernie Sanders' 2020 campaign [released a new web app](https://www.nbcnews.com/politics/2020-election/bernie-sanders-2020-campaign-unveils-app-increase-its-voter-database-n999206) last month named [BERN](https://app.berniesanders.com/). The goal of BERN is simple: to gather as much information as they can on as many voters in the United States as they can, and make their grassroots army of enthusiastic supporters do the work. It's undoubtedly a smart strategy, but also a concerning one for myself and other privacy advocates.
<img src="/static/images/notes/bernie-sanders-bern-app-data/sad-bernie.jpg" width="865" height="433" alt="Sad Bernie" />
BERN has two features: one called "Friend-to-Friend" (described as "add everyone in your network") and another called "Community Canvassing" (described as "talk to people around you every day, e.g. on the bus, outside the grocery store, at a park"). Both of these involve phoning home to Sanders HQ with the following information on anybody you know or meet:
- Level of support for Bernie Sanders (from 1 to 7)
- How you know this person (family, neighbor, classmate, etc.)
- If they're a student (and specifically which college they attend)
- If they're a union member (and which union)
- Issues that are "most important" to them
- List of other candidates they might support
- Their phone number
- Their email address
But how do I know who I know, you might ask? BERN's [FAQ page](https://app.berniesanders.com/help/app-frequently-asked-questions/) helpfully answers this:
> **Brainstorm a list of your contacts.** Think about who you have come to know over the course of your life. How do you know who you know? On a piece of paper or in a spreadsheet, write down as many names of people you know. Some ideas for brainstorming:
>
> - Go through your phone book or, if you use Facebook, your Facebook friend list.
> - Who would you invite to your birthday party or wedding? Where have you lived throughout your life? Who did you know in each of the places you have lived?
>
> **Which people can I add to my contact list the BERN app?** _[sic]_
> We use the word "friend" very broadly: You can add anyone you have met and known in your life to the app.
Using either feature, a volunteer starts with a search of the database for the voter he or she is (theoretically) talking to by entering the voter's first name, last name, and location (which only requires entering the state but can be narrowed down by town and/or ZIP code). Every match pops up with each voter's age, sex, and location along with an option to add the information of someone who's not listed or still needs to register to vote.
Here's one of the instructional videos provided internally to volunteers:
<video
url={[
{ src: "/static/images/notes/bernie-sanders-bern-app-data/friend-to-friend.webm", type: "video/webm" },
{ src: "/static/images/notes/bernie-sanders-bern-app-data/friend-to-friend.mp4", type: "video/mp4" },
]}
config={{
file: {
attributes: {
poster: "/static/images/notes/bernie-sanders-bern-app-data/poster-friend-to-friend.png",
controlsList: "nodownload",
preload: "metadata",
autoPlay: false,
},
},
}}
controls={true}
/>
...and a few privacy-related questions about the friend-to-friend feature were answered by campaign staff in a separate closed webinar for volunteers this week:
<img
className="center"
src="/static/images/notes/bernie-sanders-bern-app-data/webinar-qa-1.png"
width="400"
height="155"
alt="Q&A 1"
/>
<img
className="center"
src="/static/images/notes/bernie-sanders-bern-app-data/webinar-qa-2.png"
width="400"
height="184"
alt="Q&A 2"
/>
Defenders of the BERN app have pointed out that the information used is already available from public voter rolls maintained independently by each state. This is true. But these public records have never been tied to a campaign's internal voter files through a tool that's wide open to the entire internet, with incentives to add valuable data that benefits one candidate.
There were even unverified claims that [BERN was leaking voter ID numbers](https://info.idagent.com/blog/bern-app-exposes-150m-voter-records), which are the same as one's driver's license ID numbers in some states, through JSON responses in the first few days after its release. There don't be appear to be strict rate limits on calls to the API either, potentially inviting malicious actors from around the world — wink wink — to scrape personal data on tens of millions of Americans en masse.
<figure>
<img
src="/static/images/notes/bernie-sanders-bern-app-data/json-response.jpg"
width="865"
height="369"
alt="BERN's API response in Chrome DevTools"
/>
<figcaption>BERN's API response in Chrome DevTools</figcaption>
</figure>
Others have noted that web-based organizing tools like BERN have been used by campaigns at all levels since President Obama's well-oiled, futuristic machine in 2007. This is also true, and I'm a big fan of the trend they started.
But the latter category of databases — like [NationBuilder](https://nationbuilder.com/) and, more notably, [NGP VAN's VoteBuilder](https://act.ngpvan.com/votebuilder) software based on the Obama campaign's inventions and now used by almost all Democratic campaigns across the United States — are secured and strictly guarded. Volunteer accounts need to be created and approved by paid campaign organizers and are locked down to provide the bare minimum amount of information necessary for one to canvass or phone bank a shortlist of voters. Every single click is also recorded in a [detailed log](sanders-campaign-audit.pdf) down to the millisecond. (This is how [Bernie's organizers got busted](https://time.com/4155185/bernie-sanders-hillary-clinton-data/) snooping around Hillary's VoteBuilder data last cycle, by the way.)
<figure>
<a className="no-underline" href="/static/images/notes/bernie-sanders-bern-app-data/sanders-campaign-audit.pdf">
<img
src="/static/images/notes/bernie-sanders-bern-app-data/votebuilder-audit.png"
width="750"
height="447"
alt="NGP VAN's audit of the Sanders campaign's VoteBuilder activity"
/>
</a>
<figcaption>
<a href="/static/images/notes/bernie-sanders-bern-app-data/sanders-campaign-audit.pdf">
NGP VAN's audit of the Sanders campaign's VoteBuilder activity
</a>
</figcaption>
</figure>
BERN is taking this to an unprecedented level. Allowing anybody on the internet to sign up and add others' personal information to the campaign's database without their knowledge is troubling, especially when you consider the gamified "points" system they've added as an incentive to report as much information on as many people as possible.
<figure>
<img
src="/static/images/notes/bernie-sanders-bern-app-data/reddit-bros.png"
width="600"
height="301"
alt="BERN discussion on /r/SandersForPresident thread"
/>
<figcaption>
<a
href="https://www.reddit.com/r/SandersForPresident/comments/bi15la/new_get_the_official_bernie_sanders_2020_app_bern/elxi85m/"
target="_blank"
rel="noopener noreferrer"
>
BERN discussion on /r/SandersForPresident thread
</a>
</figcaption>
</figure>
In addition to the points system, it was revealed in the webinar mentioned above that the campaign is planning on giving out shiny rewards based on how many friends one adds, setting expectations at 50+ contacts to reach the "Bernie Super Bundler" tier — whatever that means.
<img
className="center"
src="/static/images/notes/bernie-sanders-bern-app-data/webinar-slide-1.png"
width="700"
height="451"
alt="Webinar Slide 1"
/>
In the middle of the webinar, the organizer also paused the presentation for _fifteen minutes_ — complete with a countdown clock — and told volunteers to race to add as many of their friends as possible in that time. She announced afterwards that participants added 20 to 40 friends into the app on average, with some allegedly adding close to 100 in fifteen minutes.
<img
className="center"
src="/static/images/notes/bernie-sanders-bern-app-data/webinar-slide-2.png"
width="700"
height="451"
alt="Webinar Slide 2"
/>
The [Privacy Policy link](https://berniesanders.com/privacy-policy/) at the bottom of the app links to a generic policy that looks like it's been copied from a default Wix website. There's no mention of the BERN app, no details of how they explicitly use our information, and no sign of an opt-out procedure.
Without getting too political — everyone who knows me already knows [what I think of Bernie](/notes/millenial-with-hillary-clinton/) — it's hard to refute that his "bros" are [notorious for harassment](https://www.washingtonpost.com/news/the-fix/wp/2016/06/07/the-bernie-bros-are-out-in-full-force-harassing-female-reporters/?utm_term=.795f3a6a6ac9) and internet trolling. Giving them any additional information beyond the Twitter handles of their targets is surely not going to help detoxify the discourse this time around.
Count me out of feeling the Bern and the BERN. Just regular old heartburn for me. 🤢

View File

@ -0,0 +1,41 @@
---
title: "Does Cloudflare's 1.1.1.1 DNS Block Archive.is?"
date: 2019-05-04 09:35:12-0400
description: "Short answer: no. Quite the opposite, actually — Archive.is is intentionally blocking 1.1.1.1 users. Here's why."
tags:
- Cloudflare
- DNS
- Networking
- Privacy
- Temper Tantrums
image: "/static/images/notes/cloudflare-dns-archive-is-blocked/archive-is.png"
---
**tl;dr:** No. Quite the opposite, actually — [Archive.is](https://archive.is/)'s owner is intentionally blocking 1.1.1.1 users.
<img
src="/static/images/notes/cloudflare-dns-archive-is-blocked/archive-is.png"
width="865"
height="180"
alt="Archive.today screenshot"
/>
A [recent post on Hacker News](https://news.ycombinator.com/item?id=19828317) pointed out something I've noticed myself over the past year — the [Archive.is](https://archive.is/) website archiving tool (aka [Archive.today](https://archive.today/) and a few other TLDs) appears unresponsive when I'm on my home network, where I use Cloudflare's fantastic public DNS service, [1.1.1.1](https://1.1.1.1/). I didn't connect the two variables until I read this post, where somebody noticed that the Archive.is domain resolves for [Google's 8.8.8.8](https://developers.google.com/speed/public-dns/) DNS, but not 1.1.1.1. An interesting and timeless debate on [privacy versus convenience](https://www.adweek.com/digital/why-consumers-are-increasingly-willing-to-trade-privacy-for-convenience/) ensued.
[Matthew Prince](https://twitter.com/eastdakota), the CEO and co-founder of [Cloudflare](https://www.cloudflare.com/) (who's also [very active](https://news.ycombinator.com/user?id=eastdakota) on Hacker News), responded to the observation [with a detailed explanation](https://news.ycombinator.com/item?id=19828702) of what's happening behind the scenes, revealing that Archive.is's owner is actively refusing to resolve their own website for 1.1.1.1 users because Cloudflare's DNS offers **_too much_** privacy. Excerpt below, emphasis mine:
> We don't block archive.is or any other domain via 1.1.1.1. [...] Archive.is's authoritative DNS servers **return bad results to 1.1.1.1 when we query them**. I've proposed we just fix it on our end but our team, quite rightly, said that too would violate the integrity of DNS and the privacy and security promises we made to our users when we launched the service. [...] The archive.is owner has explained that **he returns bad results to us because we don't pass along the EDNS subnet information**. This information leaks information about a requester's IP and, in turn, sacrifices the privacy of users. [Read more &raquo;](https://news.ycombinator.com/item?id=19828702)
In other words, Archive.is's nameservers throw a hissy fit and return a bogus IP when Cloudflare **doesn't** leak your geolocation info to them via the optional [EDNS client subnet feature](https://tools.ietf.org/html/rfc7871). The owner of Archive.is has plainly admitted this with [a questionable claim](https://twitter.com/archiveis/status/1018691421182791680) (in my opinion) about the lack of EDNS information causing him "so many troubles."
<tweet id="1018691421182791680" />
He's even gone as far as [replying to support requests](https://community.cloudflare.com/t/archive-is-error-1001/18227/7) by telling people to switch to Google's DNS, which — surprise! — offers your location to nameservers [with pleasure](https://developers.google.com/speed/public-dns/docs/ecs).
I wrote the [following reply](https://news.ycombinator.com/item?id=19828898) to Matthew, praising his team's focus on the big picture:
> Honestly, Cloudflare choosing _not_ to hastily slap a band-aid on a problem like this just makes me feel more compelled to continue using 1.1.1.1.
>
> I hesitate to compare this to Apple calling themselves "courageous" when removing the headphone jack, but in this case, I think the word is appropriate. I'll happily stand behind you guys if you take some PR hits while forcing the rest of the industry to make DNS safer — since it is understandable, admittedly, for users to conclude that "Cloudflare is blocking websites, sound the alarms!" at first glance.
Sure, it's annoying that I'll need to use a VPN or change my DNS resolvers to use a pretty slick (and otherwise convenient) website archiver. But I'm more happy to see that Cloudflare is playing the privacy long-game, even at the risk of their users concluding that they're blocking websites accessible to everyone else on the internet.

View File

@ -0,0 +1,148 @@
---
title: 'Cool Bash Tricks for Your Terminal''s "Dotfiles"'
date: 2018-12-10 20:01:50-0400
description: "Bashfiles usually contain shortcuts compatible with Bash terminals to automate convoluted commands. Here's a summary of the ones I find most helpful that you can add to your own .bash_profile or .bashrc file."
tags:
- Dotfiles
- Hacks
- macOS
- Programming
- Terminal
- Tutorial
image: "/static/images/notes/cool-bash-tricks-for-your-terminal-dotfiles/terminal.png"
---
<img
className="center"
src="/static/images/notes/cool-bash-tricks-for-your-terminal-dotfiles/terminal.png"
width="320"
height="284"
alt="Terminal.app on macOS"
/>
You may have noticed the recent trend of techies [posting their "dotfiles" on GitHub](https://github.com/topics/dotfiles) for the world to see. These usually contain shortcuts compatible with Bash terminals to automate convoluted commands that, I'll admit, I needed to Google every single time.
My [full dotfiles are posted at this Git repository](https://github.com/jakejarvis/dotfiles), but here's a summary of the ones I find most helpful that you can add to your own `.bash_profile` or `.bashrc` file.
---
Check your current IP address (IPv4 or IPv6 or both) — uses [my ⚡ fast simpip server!](https://github.com/jakejarvis/simpip)
```bash
alias ip4="curl -4 simpip.com --max-time 1 --proto-default https --silent"
alias ip6="curl -6 simpip.com --max-time 1 --proto-default https --silent"
alias ip="ip4; ip6"
```
Check your current local IP address:
```bash
alias iplocal="ipconfig getifaddr en0"
```
Check, clear, set ([Google DNS](https://developers.google.com/speed/public-dns/) or [Cloudflare DNS](https://1.1.1.1/) or custom), and flush your computer's DNS, overriding your router:
```bash
alias dns-check="networksetup -setdnsservers Wi-Fi"
alias dns-clear="networksetup -getdnsservers Wi-Fi"
alias dns-set-cloudflare="dns-set 1.1.1.1 1.0.0.1"
alias dns-set-google="dns-set 8.8.8.8 8.8.4.4"
alias dns-set-custom="networksetup -setdnsservers Wi-Fi " # example: dns-set-custom 208.67.222.222 208.67.220.220
alias dns-flush="sudo killall -HUP mDNSResponder; sudo killall mDNSResponderHelper; sudo dscacheutil -flushcache"
```
Start a simple local web server in current directory:
```bash
alias serve="python -c 'import SimpleHTTPServer; SimpleHTTPServer.test()'"
```
Test your internet connection's speed (uses 100MB of data):
```bash
alias speed="wget -O /dev/null http://cachefly.cachefly.net/100mb.test"
```
Query DNS records of a domain:
```bash
alias digg="dig @8.8.8.8 +nocmd any +multiline +noall +answer" # example: digg google.com
```
Make a new directory and change directories into it.
```bash
mkcd() {
mkdir -p -- "$1" &&
cd -P -- "$1"
}
```
Unhide and rehide hidden files and folders on macOS:
```bash
alias unhide="defaults write com.apple.finder AppleShowAllFiles -bool true && killall Finder"
alias rehide="defaults write com.apple.finder AppleShowAllFiles -bool false && killall Finder"
```
Force empty trash on macOS:
```bash
alias forcetrash="sudo rm -rf ~/.Trash /Volumes/*/.Trashes"
```
Quickly lock your screen on macOS:
```bash
alias afk="/System/Library/CoreServices/Menu\ Extras/User.menu/Contents/Resources/CGSession -suspend"
```
Update Homebrew packages, global NPM packages, Ruby Gems, and macOS in all one swoop:
```bash
alias update="brew update; brew upgrade; brew cleanup; npm install npm -g; npm update -g; sudo gem update --system; sudo gem update; sudo gem cleanup; sudo softwareupdate -i -a;"
```
Copy your public key to the clipboard:
```bash
alias pubkey="more ~/.ssh/id_rsa.pub | pbcopy | echo '=> Public key copied to pasteboard.'"
```
Undo the most recent commit in current Git repo:
```bash
alias gundo="git push -f origin HEAD^:master"
```
Un-quarantine an "unidentified developer's" application [blocked by Gatekeeper](https://support.apple.com/en-us/HT202491) on macOS's walled ~~prison~~ garden:
```bash
alias unq="sudo xattr -rd com.apple.quarantine"
```
Quickly open a Bash prompt in a running Docker container:
```bash
docker-bash() {
docker exec -ti $1 /bin/bash
}
```
Pull updates for all Docker images with the tag "latest":
```bash
alias docker-latest="docker images --format '{{.Repository}}:{{.Tag}}' | grep :latest | xargs -L1 docker pull"
```
This odd hack is needed to run any of these aliases as sudo:
```bash
alias sudo="sudo "
```
---
[View all of my dotfiles here](https://github.com/jakejarvis/dotfiles) or [check out other cool programmers' dotfiles over at this amazing collection](https://dotfiles.github.io/).

View File

@ -0,0 +1,219 @@
---
title: "COVID-19 vs. the Open Source Community ⚔️"
date: 2020-03-23 15:17:09-0400
description: "The open source community is rallying together like no other to provide coronavirus information to the public in innovative ways."
tags:
- Open Source
- COVID-19
- Coronavirus
- Public Health
- GitHub
image: "images/covid19dashboards.png"
---
We're all quickly learning that worldwide pandemics can bring out both [the best](https://www.vox.com/culture/2020/3/13/21179293/coronavirus-italy-covid19-music-balconies-sing) and [the worst](https://twitter.com/9NewsAUS/status/1236088663093608448) of humanity. But one thing has become readily apparent to me — outside of the large teams of medical professionals risking their lives right this minute, the open source community stands alone in its ability to rapidly organize in the midst of chaos to give back to the world and, in this case, make it safer for all of us.
These are just a few incredible open source projects that didn't exist a few months ago, but rapidly formed teams of dozens of contributors to fill both big needs and small niches in the fight to defeat the novel coronavirus, aka [**COVID-19**](https://www.cdc.gov/coronavirus/2019-nCoV/index.html).
## [The COVID Tracking Project](https://covidtracking.com/) <octocat repo="COVID19Tracking/website" />
Now that Americans are _finally_ starting to get tested for the coronavirus, information and statistics about the results are being released state-by-state, which has led to a scattering of primary sources across the web, each releasing [different figures in different forms](https://docs.google.com/document/d/1OyN6_1UeDePwPwKi6UKZB8GwNC7-kSf1-BO2af8kqVA/edit). The [COVID Tracking Project](https://covidtracking.com/) collects as much information as possible from each local health authority's website and puts everything together in [easy-to-digest tables](https://covidtracking.com/data/), as well as [spreadsheets](https://docs.google.com/spreadsheets/u/2/d/e/2PACX-1vRwAqp96T9sYYq2-i7Tj0pvTf6XVHjDSMIKBdZHXiCGGdNC0ypEU9NbngS8mxea55JuCFuua1MUeOj5/pubhtml) and a [public API](https://covidtracking.com/api/).
The maintainers are also [fully transparent](https://covidtracking.com/about-tracker/) about their process and take great care to annotate individual figures with the methodology used to arrive at each, which has earned them the [trust](https://covidtracking.com/#press) of even the largest national news organizations reporting on COVID-19.
<figure>
<a class="no-underline" href="https://covidtracking.com/" target="_blank" rel="noopener noreferrer">
<img
className="center"
src="/static/images/notes/coronavirus-open-source/covidtracking.png"
width="680"
height="328"
alt="The COVID Tracking Project"
/>
</a>
</figure>
## [#findthemasks](https://findthemasks.com/) <octocat repo="r-pop/findthemasks" />
This one might be my favorite, simply because of its laser-like focus on solving a very specific (yet catastrophic) problem. The United States is [already running out](https://www.nytimes.com/2020/03/19/health/coronavirus-masks-shortage.html) of [personal protective equipment (PPE)](https://www.fda.gov/medical-devices/general-hospital-devices-and-supplies/personal-protective-equipment-infection-control) for the healthcare professionals on the front lines of this crisis. [#findthemasks.com](https://findthemasks.com/) has gathered specific donation requests and points of contact from hospitals around the country in desperate need of basic supplies.
_Please_ look up your local hospitals on [#findthemasks](https://findthemasks.com/#sites) and follow their instructions to donate anything you have hoarded — it's likely the single most impactful thing you can do at this point. If you don't see your local hospital, or don't feel comfortable shipping equipment to any hospital listed, you can also visit [PPE Link](https://ppelink.org/ppe-donations/) and they will connect you with hospitals in your area.
<figure>
<a class="no-underline" href="https://findthemasks.com/" target="_blank" rel="noopener noreferrer">
<img
className="center"
src="/static/images/notes/coronavirus-open-source/findthemasks.png"
width="600"
height="295"
alt="#findthemasks"
/>
</a>
</figure>
## [#StayTheFuckHome](https://staythefuckhome.com/) <octocat repo="flore2003/staythefuckhome" />
I figured I'd throw in this cheeky website broadcasting a simple but serious message: **STAY THE FUCK HOME!!!** If you're _still_ not convinced of the importance of this "suggestion," give their ["Self-Quarantine Manifesto"](https://staythefuckhome.com/) a quick read. Now.
The [GitHub community](https://github.com/flore2003/staythefuckhome/pulls?q=is%3Apr) has translated the instructional essay into over a dozen different languages — including a [safe-for-work version](https://staythefuckhome.com/sfw/), if that helps — and they're [looking for more translators](https://github.com/flore2003/staythefuckhome#contributing) if you're multilingual and need something besides Netflix to fill your time with while you **_stay the fuck home!_** 😉
<figure>
<a class="no-underline" href="https://staythefuckhome.com/" target="_blank" rel="noopener noreferrer">
<img
className="center"
src="/static/images/notes/coronavirus-open-source/staythefuckhome.png"
width="600"
height="215"
alt="#StayTheFuckHome"
/>
</a>
</figure>
## [COVID-19 Dashboards](https://covid19dashboards.com/) <octocat repo="github/covid19-dashboard" />
This collection of various visualizations is fascinating (and sobering) to look at. If you're smarter than I am and have experience in data analysis, their team (led by a [GitHub engineer](https://github.com/hamelsmu)) would be more than happy to [add your contribution](https://github.com/github/covid19-dashboard/blob/master/CONTRIBUTING.md) to the site — they're using [Jupyter Notebooks](https://jupyter.org/) and [fastpages](https://github.com/fastai/fastpages).
<figure>
<a class="no-underline" href="https://covid19dashboards.com/" target="_blank" rel="noopener noreferrer">
<img
className="center"
src="/static/images/notes/coronavirus-open-source/covid19dashboards.png"
width="580"
height="442"
alt="COVID-19 Dashboards"
/>
</a>
</figure>
## [CoronaTracker](https://coronatracker.samabox.com/) <octocat repo="MhdHejazi/CoronaTracker" />
CoronaTracker is a _beautiful_ cross-platform app for iOS and macOS with intuitive maps and charts fed by reputable live data. Apple is [being justifiably picky](https://developer.apple.com/news/?id=03142020a) about "non-official" Coronavirus apps in their App Store ([so is Google](https://blog.google/inside-google/company-announcements/coronavirus-covid19-response/), by the way) but you can still [download the macOS app directly](https://coronatracker.samabox.com/) or [compile the iOS source code](https://github.com/MhdHejazi/CoronaTracker#1-ios-app) yourself using Xcode if you wish.
<figure>
<a class="no-underline" href="https://coronatracker.samabox.com/" target="_blank" rel="noopener noreferrer">
<img
src="/static/images/notes/coronavirus-open-source/coronatracker.png"
width="865"
height="417"
alt="CoronaTracker"
/>
</a>
</figure>
## [Staying Home Club](https://stayinghome.club/) <octocat repo="phildini/stayinghomeclub" />
A bit more family-friendly than [#StayTheFuckHome](https://staythefuckhome.com/), the [Staying Home Club](https://stayinghome.club/) is maintaining a running list of over a thousand companies and universities mandating that employees and students work from home, as well as events that have been canceled or moved online. Quarantining yourself might feel lonely, but here's solid proof that you're far from alone right now.
<figure>
<a class="no-underline" href="https://stayinghome.club/" target="_blank" rel="noopener noreferrer">
<img
className="center"
src="/static/images/notes/coronavirus-open-source/stayinghome.png"
width="600"
height="137"
alt="Staying Home Club"
/>
</a>
</figure>
## [Nextstrain for nCoV](https://nextstrain.org/ncov) <octocat repo="nextstrain/ncov" />
This one is a bit over my head, but apparently [Nextstrain](https://nextstrain.org/) is a pretty impressive open-source service targeted at genome data analysis and visualization of different pathogens. Their [COVID-19 page](https://nextstrain.org/ncov) is still awe-inspiring to look at for a layman like me, but probably a thousand times more so if you're an actual scientist — in which case, the [genome data they've open-sourced](https://github.com/nextstrain/ncov) might be of interest to you.
<figure>
<a class="no-underline" href="https://nextstrain.org/ncov" target="_blank" rel="noopener noreferrer">
<img
src="/static/images/notes/coronavirus-open-source/nextstrain.png"
width="865"
height="345"
alt="Nextstrain for nCOV"
/>
</a>
</figure>
## [Johns Hopkins 2019-nCoV Data](https://systems.jhu.edu/research/public-health/ncov/) <octocat repo="CSSEGISandData/COVID-19" />
Johns Hopkins University's [visual COVID-19 global dashboard](https://www.arcgis.com/apps/opsdashboard/index.html#/bda7594740fd40299423467b48e9ecf6) has been bookmarked as my go-to source of information since the beginning of this crisis earlier this year. Now, JHU's [Center for Systems Science and Engineering](https://systems.jhu.edu/) has open-sourced [their data and analysis](https://github.com/CSSEGISandData/COVID-19) for anybody to use.
<figure>
<a
class="no-underline"
href="https://systems.jhu.edu/research/public-health/ncov/"
target="_blank"
rel="noopener noreferrer"
>
<img
src="/static/images/notes/coronavirus-open-source/hopkins.png"
width="865"
height="426"
alt="Johns Hopkins 2019-nCoV Data"
/>
</a>
</figure>
## [COVID-19 Scenarios](https://neherlab.org/covid19/) <octocat repo="neherlab/covid19_scenarios" />
COVID-19 Scenarios will probably hit everyone in a different way, depending on your levels of optimism and/or pessimism right now. It uses [advanced scientific models](https://neherlab.org/covid19/about) to predict the future of the virus based on past data and future variables and assumptions you can tinker with yourself.
The maintainers at the [Neher Lab in Basel, Switzerland](https://neherlab.org/) even have a [discussion thread](https://github.com/neherlab/covid19_scenarios/issues/18) and an [open chatroom](https://spectrum.chat/covid19-scenarios/general/questions-discussions~8d49f461-a890-4beb-84f7-2d6ed0ae503a) set up for both scientists and non-scientists to ask questions and post ideas, which I find really nice of them!
<figure>
<a class="no-underline" href="https://neherlab.org/covid19/" target="_blank" rel="noopener noreferrer">
<img
className="center"
src="/static/images/notes/coronavirus-open-source/scenarios.png"
width="740"
height="433"
alt="COVID-19 Scenarios"
/>
</a>
</figure>
## [Corona Data Scraper](https://coronadatascraper.com/#home) <octocat repo="lazd/coronadatascraper" />
Similar to the [COVID Tracking Project](https://covidtracking.com/) above, the [Corona Data Scraper](https://coronadatascraper.com/#home) has set up an automated process to scrape verified data from across the web to form massive CSV spreadsheets and JSON objects. They even [rate the quality](https://github.com/lazd/coronadatascraper#source-rating) of each source to prioritize data accordingly.
<figure>
<a class="no-underline" href="https://coronadatascraper.com/#home" target="_blank" rel="noopener noreferrer">
<img
className="center"
src="/static/images/notes/coronavirus-open-source/coronadatascraper.png"
width="750"
height="358"
alt="Corona Data Scraper"
/>
</a>
</figure>
## [Folding@home](https://foldingathome.org/covid19/) <octocat repo="FoldingAtHome/coronavirus" />
[Folding@home](https://foldingathome.org/) has been around [_forever_](https://en.wikipedia.org/wiki/Folding@home). I remember installing it on my family's home computer as a curious kid and making my father infuriated over how slow it got. But they [switched gears this month](https://foldingathome.org/2020/03/15/coronavirus-what-were-doing-and-how-you-can-help-in-simple-terms/) from using our computers to crunch various proteins and molecules in the background, and all of their power is now going towards discovering unknown "folds" in the coronavirus, which might be able to lead scientists to find better cures and potential vaccines.
You can [download their software here](https://foldingathome.org/start-folding/) to donate some idle computing power to their efforts — they definitely know what they're doing by now, after pioneering en-masse distributed computing 20 years ago.
**Fun fact:** The team behind Folding@home has seen a [**huge** spike in computational power](https://www.reddit.com/r/pcmasterrace/comments/flgm7q/ama_with_the_team_behind_foldinghome_coronavirus/) this month after cryptominers started mining coronavirus proteins instead of boring, old Ethereum with their insanely overpowered GPUs! 👏
<video url="https://www.youtube-nocookie.com/watch?v=NTLU1anxe8c" controls />
## [Coronavirus Tracker API](https://coronavirus-tracker-api.herokuapp.com/v2/locations) <octocat repo="ExpDev07/coronavirus-tracker-api" />
To wrap this list up, I thought I'd include [yet another API](https://github.com/ExpDev07/coronavirus-tracker-api) fed by multiple data sources that you can use to create your own open-source project if any of these inspired you. This one is incredibly flexible in terms of [query parameters and endpoints](https://github.com/ExpDev07/coronavirus-tracker-api#api-endpoints) but they all return simple JSON responses like we all know and love.
<figure>
<a
class="no-underline"
href="https://coronavirus-tracker-api.herokuapp.com/v2/locations"
target="_blank"
rel="noopener noreferrer"
>
<img
className="center"
src="/static/images/notes/coronavirus-open-source/tracker-api.png"
width="712"
height="371"
alt="Coronavirus Tracker API"
/>
</a>
</figure>
### Stay safe (and [home](https://staythefuckhome.com/ "One last time...")), friends! ❤️

View File

@ -0,0 +1,64 @@
---
title: "Animated Waving Hand Emoji 👋 Using CSS"
date: 2019-04-17 14:20:10-0400
description: "How to make the 👋 waving hand emoji actually wave using pure CSS animation!"
tags:
- CSS
- Animation
- Emoji
- Keyframes
- Cool Tricks
image: "/static/images/notes/css-waving-hand-emoji/codepen.png"
---
## Howdy, friends! 👋
If you examine [my homepage](/) long enough, you might notice the 👋 hand emoji at the top subtly waving at you. This was easily accomplished using a few lines of CSS with a feature called [`@keyframes`](https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes) — no bulky GIFs involved, and no JS mess or jQuery overkill required.
Below are the code snippets you can grab and customize to make your own ["waving hand" 👋](https://emojipedia.org/waving-hand-sign/) emojis **_actually wave_**, and a [CodePen playground](https://codepen.io/jakejarvis/pen/pBZWZw) for live testing.
## Demo
<iframe
height="500"
width="100%"
src="https://codepen.io/jakejarvis/embed/pBZWZw/?theme-id=light&amp;default-tab=css,result"
scrolling="no"
></iframe>
## CSS
<!-- prettier-ignore -->
```css
.wave {
animation-name: wave-animation; /* Refers to the name of your @keyframes element below */
animation-duration: 2.5s; /* Change to speed up or slow down */
animation-iteration-count: infinite; /* Never stop waving :) */
transform-origin: 70% 70%; /* Pivot around the bottom-left palm */
display: inline-block;
}
<!-- prettier-ignore -->
@keyframes wave-animation {
0% { transform: rotate( 0.0deg) }
10% { transform: rotate(14.0deg) } /* The following five values can be played with to make the waving more or less extreme */
20% { transform: rotate(-8.0deg) }
30% { transform: rotate(14.0deg) }
40% { transform: rotate(-4.0deg) }
50% { transform: rotate(10.0deg) }
60% { transform: rotate( 0.0deg) } /* Reset for the last half to pause */
100% { transform: rotate( 0.0deg) }
}
```
## HTML
```html
<h1>Hi there! <span class="wave">👋</span></h1>
```
---
That's it! More hands and skin tones can be [found on 📕 Emojipedia](https://emojipedia.org/search/?q=waving+hand).
**👋🏼 Toodles!**

244
notes/dark-mode.mdx Normal file
View File

@ -0,0 +1,244 @@
---
title: "How To: Add Dark Mode to a Website 🌓"
date: 2021-10-15 08:56:33-0400
description: "Simple dark mode switching using local storage, OS preference detection, and minimal JavaScript."
tags:
- JavaScript
- NPM
- CSS
- Dark Mode
- How To
- Tutorial
---
Love it or hate it, it seems that the [dark mode fad](https://en.wikipedia.org/wiki/Light-on-dark_color_scheme) is here to stay, especially now that more and more devices have [OLED screens](https://www.macrumors.com/2019/10/21/ios-13-dark-mode-extends-iphone-battery-life/) that display true blacks... which means that these trendsetters might go blind from your site's insanely white background if you're behind the curve and don't offer your own dark mode.
It _is_ possible to use [pure CSS3 media queries to do this](https://css-tricks.com/dark-modes-with-css/) by reading a user's system and/or browser preference, which might be enough if you're okay with **only** supporting the [latest, cutting-edge browsers](https://caniuse.com/#feat=prefers-color-scheme) and OSes. But if you want your own button on your website that switches back and forth between the two modes, there's no avoiding getting your hands a little dirty with some JavaScript.
I've written a simple implementation below, which...
- Defaults to a user's system preference, until they press your toggle to set it themselves
- Listens for clicks on any element of your choosing — just set the class to `dark-mode-toggle`. For example:
```html
<button class="dark-mode-toggle">💡 Switch Themes</button>
```
- Remembers the visitor's preference between visits using the [local storage](https://www.w3schools.com/html/html5_webstorage.asp) of the their browser (not cookies, please don't use cookies!)
- Switches your `<body>`'s class between `light` and `dark`...
...meaning that any CSS selectors beginning with `body.dark` or `body.light` will only apply when the respective mode is active. A good place to start is by separating any color rules — your background, text, links, etc. — into a different section of your CSS. Using [SASS or SCSS](https://sass-lang.com/) makes this a whole lot [easier with nesting](https://sass-lang.com/guide#topic-3) but is not required; this was written with a [KISS](https://getyarn.io/yarn-clip/embed/eed08f4f-d1c9-4cc0-b041-f280a5dbf0a5?autoplay=false) mentality.
<iframe
src="/dark-mode-example/example.html"
title="Dark Mode Example"
sandbox="allow-same-origin allow-scripts allow-popups"
style={{
height: "190px",
width: "100%",
maxWidth: "650px",
display: "block",
boxSizing: "border-box",
margin: "0 auto",
border: "2px solid #cccccc",
}}
></iframe>
A _very_ barebones example is embedded above ([view the source here](https://github.com/jakejarvis/dark-mode-example), or [open in a new window](/dark-mode-example/example.html) if your browser is blocking the frame) and you can try it out on this site by clicking the 💡 lightbulb in the upper right corner of this page. You'll notice that the dark theme sticks when refreshing this page, navigating between other pages, or if you were to return to this example weeks from now.
---
### ⚡ Update: Now Available on [NPM](https://www.npmjs.com/package/dark-mode-switcheroo)!
I have cleaned up this code a bit, added a few features, and packaged it as an [📦 NPM module](https://www.npmjs.com/package/dark-mode-switcheroo) (zero dependencies and still [only ~500 bytes](https://bundlephobia.com/package/dark-mode-switcheroo) minified and gzipped!). Here's a small snippet of the updated method for the browser (pulling the module from [UNPKG](https://unpkg.com/browse/dark-mode-switcheroo/)), but definitely [read the readme](https://github.com/jakejarvis/dark-mode#readme) for much more detail on the API.
```html
<button class="dark-mode-toggle" style="visibility: hidden;">💡 Click to see the light... or not.</button>
<script src="https://unpkg.com/dark-mode-switcheroo/dist/dark-mode.min.js"></script>
<script>
window.darkMode.init({
toggle: document.querySelector(".dark-mode-toggle"),
classes: {
light: "light",
dark: "dark",
},
default: "light",
storageKey: "dark_mode_pref",
onInit: function (toggle) {
toggle.style.visibility = "visible"; // toggle appears now that we know JS is enabled
},
onChange: function (theme, toggle) {
console.log("Theme is now " + theme);
},
});
</script>
```
You can also install it [straight from NPM](https://www.npmjs.com/package/dark-mode-switcheroo) (`npm install dark-mode-switcheroo` or `yarn add dark-mode-switcheroo`) and simply include the ESM module, which works great when bundling using [Webpack](https://webpack.js.org/), [Browserify](https://browserify.org/), [Parcel](https://parceljs.org/), [esbuild](https://esbuild.github.io/), etc.
```js
import { init } from "dark-mode-switcheroo";
init({
// ...same options as browser code.
});
```
The [example HTML and CSS below](#html-css) is still helpful for reference.
---
### [Minified JS](https://raw.githubusercontent.com/jakejarvis/dark-mode-example/gh-pages/dark-mode.min.js) (410 bytes gzipped! 📦):
<!-- prettier-ignore -->
```js
/*! Dark mode switcheroo | MIT License | jrvs.io/darkmode */
(function(){var e=window,t=e.document,i=t.body.classList,a=localStorage,c="dark_mode_pref",d=a.getItem(c),n="dark",o="light",r=o,s=t.querySelector(".dark-mode-toggle"),m=r===n,l=function(e){i.remove(n,o);i.add(e);m=e===n};d===n&&l(n);d===o&&l(o);if(!d){var f=function(e){return"(prefers-color-scheme: "+e+")"};e.matchMedia(f(n)).matches?l(n):e.matchMedia(f(o)).matches?l(o):l(r);e.matchMedia(f(n)).addListener((function(e){e.matches&&l(n)}));e.matchMedia(f(o)).addListener((function(e){e.matches&&l(o)}))}if(s){s.style.visibility="visible";s.addEventListener("click",(function(){if(m){l(o);a.setItem(c,o)}else{l(n);a.setItem(c,n)}}),!0)}})();
```
### Full JS:
<!-- prettier-ignore -->
```js
/*! Dark mode switcheroo | MIT License | jrvs.io/darkmode */
(function () {
// improve variable mangling when minifying
var win = window;
var doc = win.document;
var body = doc.body;
var classes = body.classList;
var storage = localStorage;
// check for preset `dark_mode_pref` preference in local storage
var pref_key = 'dark_mode_pref';
var pref = storage.getItem(pref_key);
// change CSS via these <body> classes:
var dark = 'dark';
var light = 'light';
// which class is <body> set to initially?
var default_theme = light;
// use an element with class `dark-mode-toggle` to trigger swap when clicked
var toggle = doc.querySelector('.dark-mode-toggle');
// keep track of current state no matter how we got there
var active = (default_theme === dark);
// receives a class name and switches <body> to it
var activateTheme = function (theme) {
classes.remove(dark, light);
classes.add(theme);
active = (theme === dark);
};
// if user already explicitly toggled in the past, restore their preference
if (pref === dark) activateTheme(dark);
if (pref === light) activateTheme(light);
// user has never clicked the button, so go by their OS preference until/if they do so
if (!pref) {
// returns media query selector syntax
var prefers = function (theme) {
return '(prefers-color-scheme: ' + theme + ')';
};
// check for OS dark/light mode preference and switch accordingly
// default to `default_theme` set above if unsupported
if (win.matchMedia(prefers(dark)).matches)
activateTheme(dark);
else if (win.matchMedia(prefers(light)).matches)
activateTheme(light);
else
activateTheme(default_theme);
// real-time switching if supported by OS/browser
win.matchMedia(prefers(dark)).addListener(function (e) { if (e.matches) activateTheme(dark); });
win.matchMedia(prefers(light)).addListener(function (e) { if (e.matches) activateTheme(light); });
}
// don't freak out if page happens not to have a toggle
if (toggle) {
// toggle re-appears now that we know user has JS enabled
toggle.style.visibility = 'visible';
// handle toggle click
toggle.addEventListener('click', function () {
// switch to the opposite theme & save preference in local storage
if (active) {
activateTheme(light);
storage.setItem(pref_key, light);
} else {
activateTheme(dark);
storage.setItem(pref_key, dark);
}
}, true);
}
})();
```
### HTML & CSS Example:
<!-- prettier-ignore -->
```html
<!doctype html>
<html>
<head>
<style>
/* rules that apply globally */
body {
font-family: system-ui, -apple-system, sans-serif;
text-align: center;
}
a {
text-decoration: none;
}
.dark-mode-toggle {
cursor: pointer;
padding: 1em;
/* hide toggle until we're sure user has JS enabled */
visibility: hidden;
}
/* theme-specific rules -- you probably only want color-related stuff here */
/* SCSS makes this a whole lot easier by allowing nesting, but is not required */
body.light {
background-color: #fff;
color: #222;
}
body.light a {
color: #06f;
}
body.dark {
background-color: #222;
color: #fff;
}
body.dark a {
color: #fe0;
}
</style>
</head>
<body class="light">
<h1>Welcome to the dark side 🌓</h1>
<p><a href="https://github.com/jakejarvis/dark-mode-example">View the source code.</a></p>
<button class="dark-mode-toggle">💡 Click to see the light... or not.</button>
<script src="dark-mode.min.js"></script>
</body>
</html>
```
---
### Further reading:
- [The Dark (Mode) Web Rises](https://charlesrt.uk/blog/the-dark-web-rises/)
- [Dark Mode vs. Light Mode: Which Is Better?](https://www.nngroup.com/articles/dark-mode/)
- [The dawn of Dark Mode](https://uxdesign.cc/the-dawn-of-dark-mode-9636d1c9bcf0)
- [Redesigning your product and website for dark mode](https://stuffandnonsense.co.uk/blog/redesigning-your-product-and-website-for-dark-mode)
- [Dark theme in a day](https://medium.com/@mwichary/dark-theme-in-a-day-3518dde2955a)

View File

@ -0,0 +1,84 @@
---
title: "Why I'm Dropping Dropbox"
date: 2019-11-20 17:22:43-0400
description: "I'm finally canceling my Dropbox Pro account and moving to iCloud Drive for synchronized cloud storage."
tags:
- Cloud Storage
- Dropbox
- Apple
- iCloud Drive
- Betrayal
image: "/static/images/notes/dropping-dropbox/email.png"
---
I've been a loyal Dropbox user since its inception as a [Y Combinator startup](https://www.ycombinator.com/apply/dropbox/) ten years ago. Having a folder on all of my devices that instantly synchronized with each other was a game-changer for me, and I grew dependent on it more and more as they gave out free storage like candy — 48 GB for having a Samsung Chromebook, 1 GB for "Posting <3 to Twitter," and so on — until I needed to upgrade to Dropbox Pro. But this month I canceled my Pro subscription after a few too many strikes.
<figure>
<img
src="/static/images/notes/dropping-dropbox/email.png"
width="504"
height="223"
alt="Deleting 401,907 files from Dropbox... 😬"
/>
<figcaption>Deleting 401,907 files from Dropbox... 😬</figcaption>
</figure>
## Five strikes, you're out...
Decisions made by the top folks at Dropbox gave me an increasingly sour taste in my mouth over the past few years. The biggest red flags were:
- Removing my long-standing 48 GB promotion for Samsung Chromebooks from 2014 with little notice, offering a free 3 GB instead and preventing me from adding new files until I forked over \$11.99/month for Dropbox Pro.
- Adding a [3-device limit](https://help.dropbox.com/account/computer-limit) for free accounts, triggering another hostage negotiation resulting in me upgrading to Pro.
- Continuously forcing [bloated updates](https://www.theverge.com/2019/6/11/18661673/new-dropbox-desktop-app-google-docs-slack-atlassian) to their once-simple macOS app down users' throats, to the point where ["the new Dropbox"](https://blog.dropbox.com/topics/product-tips/new-dropbox) was consistently eating up _over a gigabyte of RAM_ and a non-negligible chunk of CPU usage thanks to an entire web browser being embedded into it:
<tweet id="1138686582859239425" />
- Explicitly [dropping support for symlinking](https://news.ycombinator.com/item?id=20844363) (aka making aliases to) files outside of the literal `~/Dropbox` folder, which was incredibly helpful for nerds — once their main audience and biggest cheerleaders — with things like [dotfiles](https://github.com/jakejarvis/dotfiles) and Git repositories.
- ...and as a bonus, making the process of canceling Dropbox Pro incredibly convoluted, annoying, and sketchy. Here's a video demonstration via [Justin Dunham](https://twitter.com/jwyattd):
<video
url={[
{ src: "/static/images/notes/dropping-dropbox/cancel.webm", type: "video/webm" },
{ src: "/static/images/notes/dropping-dropbox/cancel.mp4", type: "video/mp4" },
]}
config={{
file: {
attributes: {
poster: "/static/images/notes/dropping-dropbox/cancel.png",
controlsList: "nodownload",
preload: "metadata",
autoPlay: false,
},
},
}}
controls={true}
/>
## Seeking an alternative...
The infamous [Apple Ecosystem™](https://medium.com/swlh/the-irresistible-lure-of-the-apple-ecosystem-81bf8d66294a) has held me firmly in its grasp for over a decade now, and the main requirement of a replacement cloud storage service for me was smooth interoperability between my MacBook, iPhone, and iPad.
<img
src="/static/images/notes/dropping-dropbox/icloud-storage.png"
width="865"
height="137"
alt="iCloud Drive storage"
/>
I've never been a proponent of leaving all your eggs in one basket. But it's hard to ignore the convenience of Apple's streamlined (and [finally](https://www.imore.com/developers-encounter-major-icloud-issues-ios-13-beta) reliable) [**iCloud Drive**](https://www.apple.com/icloud/), which is already installed on all of my devices (and actually cheaper than Dropbox gigabyte-for-gigabyte, at \$9.99/month for 2 TB). In fact, it's nearly invisible on macOS: I can simply save files in my Documents or Desktop folders as I always have and they're uploaded in the background. Git repositories now sync just fine and my files reappeared without a hitch after I recently formatted my Mac.
<img
className="center"
src="/static/images/notes/dropping-dropbox/icloud-drive.png"
width="680"
height="423"
alt="iCloud Drive"
/>
I still use (and highly recommend) [**Backblaze**](https://www.backblaze.com/) ([referral link](https://secure.backblaze.com/r/00x84e)) to backup my home folder and add a second layer of redundancy to storing all of my most important files on ["someone else's computer."](https://www.zdnet.com/article/stop-saying-the-cloud-is-just-someone-elses-computer-because-its-not/) And as long as I remember to plug in my external SSD every so often, they're also backed up locally via [Time Machine](https://support.apple.com/en-us/HT201250).
---
There are already a few Dropbox features I'm beginning to miss, like [selective sync](https://help.dropbox.com/installs-integrations/sync-uploads/selective-sync-overview), third-party integration, easier sharing, and an Android app (a man can dream, right?). But hopefully Apple continues to iterate on iCloud Drive, and it serves me well enough to not want to seek out another service for another ten years.
Thank you, Dropbox, for a fine relationship and for pioneering the consumer cloud storage industry. But for now, it's just not going to work between us. 💔

View File

@ -0,0 +1,127 @@
---
title: "Finding Candidates for Subdomain Takeovers"
date: 2019-03-10 11:19:48-0400
description: "A subdomain takeover occurs when a subdomain points to a shared hosting account that is abandoned by its owner, leaving the endpoint available to claim for yourself."
tags:
- Pentesting
- Infosec
- Subdomain Takeover
- Bug Bounty
- Tutorial
image: "images/hackerone-2.png"
---
A **subdomain takeover** occurs when a subdomain (like _example_.jarv.is) points to a shared hosting account that is abandoned by its owner, leaving the endpoint available to claim for yourself.
Not only are takeovers a fun way to dip your toes into [penetration testing](https://www.cloudflare.com/learning/security/glossary/what-is-penetration-testing/), but they can also be incredibly lucrative thanks to [bug bounty programs](https://en.wikipedia.org/wiki/Bug_bounty_program) on services like [HackerOne](https://hackerone.com/hacktivity?order_direction=DESC&order_field=popular&filter=type%3Aall&querystring=subdomain%20takeover) and [Bugcrowd](https://bugcrowd.com/programs), where corporations pay pentesters for their discoveries.
<figure>
<img
src="/static/images/notes/finding-candidates-subdomain-takeovers/hackerone-2.png"
width="620"
height="347"
alt="Huge rewards for subdomain takeovers on HackerOne."
/>
<figcaption>
<a
href="https://hackerone.com/hacktivity?querystring=subdomain%20takeover"
target="_blank"
rel="noopener noreferrer"
>
Huge rewards for subdomain takeovers on HackerOne!
</a>
</figcaption>
</figure>
For a deep dive on the implications of takeovers, which can be a pretty serious vector of attack for malicious actors to obtain information from users of the targeted company, [Patrik Hudak](https://twitter.com/0xpatrik) wrote a [great post here](https://0xpatrik.com/subdomain-takeover/). Definitely take some time to skim through it and come back here when you're ready to hunt for a potential takeover yourself.
The most common services eligible for takeovers of abandoned subdomains are the following:
- Amazon S3
- ~~Amazon CloudFront~~ [(no longer vulnerable?)](https://github.com/EdOverflow/can-i-take-over-xyz/issues/29)
- Microsoft Azure
- Heroku
- GitHub Pages
- Fastly
- Pantheon.io
- Shopify
- Tumblr
- [...and many more.](https://github.com/EdOverflow/can-i-take-over-xyz#all-entries)
---
On [my GitHub profile](https://github.com/jakejarvis/), you'll find a Go-based tool named [`subtake`](https://github.com/jakejarvis/subtake) (based on [`subjack`](https://github.com/haccer/subjack)).
This tool takes a list of [CNAME records](https://support.dnsimple.com/articles/cname-record/) to check and outputs potential takeover candidates pointing to these services. But how in the world do we get a list of every CNAME on the internet?
Conveniently, [Rapid7](https://www.rapid7.com/) publishes a monthly list for us through their [Project Sonar](https://www.rapid7.com/research/project-sonar/) survey!
> [Project Sonar](https://opendata.rapid7.com/about/) is a security research project by Rapid7 that conducts internet-wide surveys across different services and protocols to gain insights into global exposure to common vulnerabilities. The data collected is available to the public in an effort to enable security research.
One of their free monthly datasets is called [Forward DNS](https://opendata.rapid7.com/sonar.fdns_v2/), where you'll find `.json` files named `xxxx-fdns_cname.json.gz`. Within the [`subtake`](https://github.com/jakejarvis/subtake) repository, there's an automated script named [`sonar.sh`](https://github.com/jakejarvis/subtake/blob/master/sonar.sh), which downloads the dataset for you and outputs a simple text file of CNAMEs pointed to any of the services listed above. Once you've [cloned the `subtake` repository](https://github.com/jakejarvis/subtake) and grabbed the timestamp part of the filename (the string that precedes `-fdns_cname.json.gz`), usage of the script is as follows:
```bash {linenos=false}
./sonar.sh 2019-03-30-1553989414 sonar_output.txt
```
This new text file contains _both active and abandoned_ subdomains pointing to any of the services listed above — we still need to narrow it down to the takeover candidates by attempting to actually resolve each of them, which is where `subtake` comes into play. To install `subtake`, make sure [Go is installed first](https://golang.org/doc/install#install) and run the following:
```bash {linenos=false}
go get github.com/jakejarvis/subtake
```
For a detailed description of the different options you can play around with, see the [full readme on GitHub](https://github.com/jakejarvis/subtake#usage) — but here's a simple example command that uses 50 threads to take the CNAMEs listed in `sonar_output.txt` and outputs potentially vulnerable subdomains to `vulnerable.txt`.
```bash {linenos=false}
subtake -f sonar_output.txt -c fingerprints.json -t 50 -ssl -a -o vulnerable.txt
```
This could take quite a while — up to a day, depending on your CPU, memory, and bandwidth — so I usually run it on a VM in the cloud and use [Linux's `screen` command](https://www.howtoforge.com/linux_screen) to keep it running and check in periodically. There will also be many unavoidable false positives that you'll need to check yourself by trying to claim the abandoned name on the corresponding service's portal, which is why I keep using the term _potential_ takeovers.
I also have a collection of root domains of companies offering bounties through [HackerOne](https://hackerone.com/directory/) or [Bugcrowd](https://bugcrowd.com/programs) at a [different GitHub repository](https://github.com/jakejarvis/bounty-domains/). Using the [`grep`-friendly text file](https://github.com/jakejarvis/bounty-domains/blob/master/grep.txt), it's easy to use [`grep`](https://man7.org/linux/man-pages/man1/grep.1.html) to narrow down your `vulnerable.txt` list even more:
```bash {linenos=false}
grep -f grep.txt vulnerable.txt
```
---
In my view, takeovers are a fantastic way to begin a side hustle in bug bounties, simply due to the fact that once you've taken over a subdomain, you don't need to worry about another hunter beating you to the punch and reporting it before you.
Since you have this luxury of time, it becomes **_extremely important_** that you let your adrenaline subside and follow [responsible disclosure](https://www.bugcrowd.com/resource/what-is-responsible-disclosure/) guidelines — especially in the creation of a "proof of concept" file with your username at an obscure location, **not** at `index.html`. I won't go over the details of writing a report because [Patrik Hudak](https://twitter.com/0xpatrik) wrote another [great post about it here](https://0xpatrik.com/takeover-proofs/). This is an example of one of my own reports (company name censored because it has not been publicly disclosed) on [Bugcrowd](https://bugcrowd.com/programs):
> I have found three subdomains of \*\*\*\*\*\*\*\*.com vulnerable to takeovers via unclaimed endpoints at [Azure's Traffic Manager](https://azure.microsoft.com/en-us/services/traffic-manager/). I have claimed these endpoints and redirected them to a blank page to prevent a bad actor from doing so in the meantime, and hosted a POC file at obscure URLs. These are the following domains I discovered and the outdated endpoints on Azure to which they point:
>
> xxxx.\*\*\*\*\*\*\*\*.com --> aaa.trafficmanager.net
>
> yyyy.\*\*\*\*\*\*\*\*.com --> bbb.trafficmanager.net
>
> zzzz.\*\*\*\*\*\*\*\*.com --> ccc.trafficmanager.net
>
> ...and the proof-of-concept files are at the following locations:
>
> [http://xxxx.\*\*\*\*\*\*\*\*.com/poc-d4ca9e8ceb.html](#)
>
> [http://yyyy.\*\*\*\*\*\*\*\*.com/poc-d4ca9e8ceb.html](#)
>
> [http://zzzz.\*\*\*\*\*\*\*\*.com/poc-d4ca9e8ceb.html](#)
>
> I have not hosted any other file nor attempted any other vector of attack. You're probably familiar with takeovers like this by now, but through this vulnerability, it would be possible for an attacker to obtain cookies and other sensitive information from your users via phishing, cookie hijacking, or XSS. It is also possible to obtain SSL certificates for \*\*\*\*\*\*\*\*.com subdomains from CAs that only require domain validation such as [Let's Encrypt](https://letsencrypt.org/how-it-works/), but I have not attempted to do so. More info on possible attack vectors [can be found here](https://0xpatrik.com/subdomain-takeover/).
>
> Please let me know when you've received this report and I'll delete the endpoints from my personal Azure account, so you can either reclaim them or remove the subdomains entirely from your DNS records. Thanks!
I removed the company's name because an important part of responsible _disclosure_ is the _disclosure_, or lack thereof. Until the company explicitly gives permission to publicly disclose the vulnerability after patching it — and there are built-in features on both HackerOne and Bugcrowd to request this — it's **not okay** to talk about it publicly.
The `poc-d4ca9e8ceb.html` proof-of-concept file contained this single, hidden line:
```html
<!-- subdomain takeover POC by @jakejarvis on Bugcrowd -->
```
No self-promotional links or redirects, no examples of XSS/cookie hijacking to be "helpful" (no matter how harmless), no funny business of any kind.
---
I have several more [improvements](https://github.com/jakejarvis/subtake#to-do) I want to make to `subtake` (like integrating the `sonar.sh` script into the main Go executable, polishing the [all-in-one automated Docker image](https://hub.docker.com/r/jakejarvis/subtake), a self-updating list of service fingerprints, etc.) but still feel free to [make a suggestion](https://github.com/jakejarvis/subtake/issues) and/or contribute to the repository in the meantime.
Happy hunting, fellow penetrators! 😉

79
notes/github-actions.mdx Normal file
View File

@ -0,0 +1,79 @@
---
title: "I ❤️ GitHub Actions"
date: 2019-10-25 13:58:39-0400
description: "I've found a new hobby of making cool GitHub Actions, the latest tool in the CI world. Here's why."
tags:
- DevOps
- GitHub
- Continuous Integration
- Docker
- Open Source
image: "images/actions-flow.png"
---
<img
className="center"
src="/static/images/notes/github-actions/actions-flow.png"
width="780"
height="322"
alt="Example workflow for a GitHub Action"
/>
Since being accepted into the beta for [GitHub Actions](https://github.com/features/actions) a few months ago, I've found a new side hobby of whipping up new (and ideally creative) actions for anybody to add to their CI pipeline. Actions are modular steps that interact with a GitHub repository and can be coded with [Docker](https://github.com/actions/hello-world-docker-action) or [JavaScript/Node](https://github.com/actions/hello-world-javascript-action) — and either way, they can be as [simple](https://github.com/jakejarvis/wait-action) or as [complex](https://github.com/jakejarvis/lighthouse-action) as you want. But in both cases, they're incredibly fun to make and the results always scratch my itch for instant gratification.
My favorite so far is my [Lighthouse Audit action](https://github.com/jakejarvis/lighthouse-action), which spins up a headless Google Chrome instance in an Ubuntu container and runs [Google's Lighthouse tool](https://developers.google.com/web/tools/lighthouse), which scores webpages on performance, accessibility, SEO, etc. and provides actual suggestions to improve them. It's a perfect example of the power of combining containers with Git workflows.
<figure>
<img
src="/static/images/notes/github-actions/lighthouse-output.png"
width="750"
height="297"
alt="The results of a Lighthouse audit on this website, after running tests in a headless Google Chrome."
/>
<figcaption>
The results of a Lighthouse audit on this website, after running tests in a headless Google Chrome.
</figcaption>
</figure>
It's also been a fantastic avenue to dip my feet into the collaborative nature of GitHub and the open-source community. I've made some small apps in the past but these are the first projects where I'm regularly receiving new issues to help out with and impressive pull requests to merge. It's a great feeling!
Here are the actions I've made so far, sorted by popularity as of this posting:
- **[💡 🏠 Lighthouse Audit](https://github.com/jakejarvis/lighthouse-action)** — Run a [Google Chrome Lighthouse](https://developers.google.com/web/tools/lighthouse) audit on a webpage.
- **[🔄 🧺 S3 Bucket Sync](https://github.com/jakejarvis/s3-sync-action)** — Sync/upload a directory with a remote AWS S3 bucket.
- **[🗑️ Cloudflare Purge Cache](https://github.com/jakejarvis/cloudflare-purge-action)** — Purge a website's cache via the Cloudflare API.
- **[✏️ Hugo Build](https://github.com/jakejarvis/hugo-build-action)** — The static site generator [Hugo](https://github.com/gohugoio) as an action, with support for legacy versions and extended features.
- **[🔥 Firebase Deploy](https://github.com/jakejarvis/firebase-deploy-action)** — Deploy a static site to [Firebase Hosting](https://firebase.google.com/docs/hosting).
- **[🔄 Backblaze B2 Sync](https://github.com/jakejarvis/backblaze-b2-action)** — Sync a directory with a remote [Backblaze B2](https://www.backblaze.com/b2/cloud-storage.html) storage bucket.
- **[💤 Wait](https://github.com/jakejarvis/wait-action)** — A very, very simple action to sleep for a given amount of time (10s, 2m, etc.)
---
As an example of an _extremely_ simple (and almost completely unnecessary) action, the [Wait action](https://github.com/jakejarvis/wait-action) takes one input — a unit of time — and has the pipeline sleep for that amount of time. The [`Dockerfile`](https://github.com/jakejarvis/wait-action/blob/master/Dockerfile) is as simple as this:
<gist id="6a0830c7c3e514980b30fdf86b4931c5" file="Dockerfile" />
...with a super-short [`entrypoint.sh`](https://github.com/jakejarvis/wait-action/blob/master/entrypoint.sh):
<gist id="6a0830c7c3e514980b30fdf86b4931c5" file="entrypoint.sh" />
Using an action is also surprisingly simple, and more intuitive than [Travis CI](https://travis-ci.com/) or [CircleCI](https://circleci.com/), in my humble opinion. Pipelines in GitHub Actions are called ["workflows,"](https://help.github.com/en/github/automating-your-workflow-with-github-actions/configuring-a-workflow) and live in a file with [YAML syntax](https://help.github.com/en/github/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions) in `.github/workflows`. An example of a `workflow.yml` file that uses the above action to wait 10 seconds (on both pushes and pull requests) would look something like:
<gist id="6a0830c7c3e514980b30fdf86b4931c5" file="workflow.yml" />
---
For a more complex example, when I forked [Hugo](https://github.com/gohugoio/hugo) (the static site generator used to build this website) to make some small personalized changes, I also translated [their `.travis.yml` file](https://github.com/gohugoio/hugo/blob/master/.travis.yml) into a [`workflow.yml` file](https://github.com/jakejarvis/hugo-custom/blob/master/.github/workflows/workflow.yml) for practice, which simultaneously runs comprehensive unit tests on **three operating systems** (Ubuntu 18.04, Windows 10, and macOS 10.14) with the latest two Go versions _each!_ If the tests are all successful, it builds a Docker image and pushes it to both [Docker Hub](https://hub.docker.com/r/jakejarvis/hugo-custom) and the [GitHub Package Registry](https://github.com/jakejarvis/hugo-custom/packages) (also [in beta](https://github.com/features/package-registry)).
<img
src="/static/images/notes/github-actions/hugo-logs.png"
width="865"
height="418"
alt="Build logs for my Hugo fork"
/>
Then another workflow, which [lives in this website's repository](https://github.com/jakejarvis/jarv.is/blob/master/.github/workflows/gh-pages.yml), pulls that Docker image, builds the Hugo site, and pushes it to GitHub Pages. All astoundingly fast. All for free.
---
A plethora of actions is already published on the [GitHub Marketplace](https://github.com/marketplace?type=actions), with dozens more being added every week. If you are not yet in the beta, I urge you to [sign up here](https://github.com/features/actions) and give it a shot. GitHub has been very [receptive to feedback](https://github.community/t5/GitHub-Actions/bd-p/actions) (so far) and I can't wait to see GitHub Actions evolve into an enterprise-grade CI tool at the level of other competitors in this space. ❤️

View File

@ -0,0 +1,117 @@
---
title: "How To: Safely Rename `master` Branch on GitHub ✊🏾"
date: 2020-06-28 09:28:52-0400
description: 'Some of the most popular open-source projects are renaming their default branch from "master" on GitHub. Here''s how to do so, and safely.'
tags:
- How To
- Tutorial
- Git
- GitHub
- Open Source
- Black Lives Matter
image: "/static/images/notes/github-rename-master/github-default.png"
---
<img src="/static/images/notes/github-rename-master/blm-topic.png" width="865" height="162" alt="Black lives matter." />
In the midst of this year's long-overdue support of the [**Black Lives Matter**](https://blacklivesmatters.carrd.co/) movement and calls to action in the US and around the world, a [new spotlight](https://mail.gnome.org/archives/desktop-devel-list/2019-May/msg00066.html) has been placed on unchecked invocations of racially charged language in the computer science world, no matter how big or small — like the long-standing and, until recently, widely accepted terms ["master" and "slave"](https://tools.ietf.org/id/draft-knodel-terminology-00.html#master-slave) as an oppressive metaphor for ownership/importance.
When somebody pointed out the negative connotations of Git projects being created with a branch named `master` by default, and the possibility of this making minorities feel even more unwelcome in an industry already [lacking diversity](https://www.informationisbeautiful.net/visualizations/diversity-in-tech/), GitHub CEO [Nat Friedman](https://github.com/nat) quietly [announced a plan](https://twitter.com/natfriedman/status/1271253144442253312) to change this on Twitter (ignore the replies for your sanity):
<tweet id="1271253144442253312" />
I think many people misunderstood this tweet to mean GitHub will forcefully rename the `master` branch of all existing projects, which would break _millions_ of programmers' workflows. If anything, it's more likely a name such as `main` will replace `master` as **the default when creating a new repository**, but that change hasn't been made yet. [GitLab is also discussing](https://gitlab.com/gitlab-org/gitlab/-/issues/221164) a similar switch to `main` as the default name. (Ideally, these changes would be made in tandem with the actual Git codebase, too. [~~But this doesn't seem likely.~~](https://lore.kernel.org/git/CAOAHyQwyXC1Z3v7BZAC+Bq6JBaM7FvBenA-1fcqeDV==apdWDg@mail.gmail.com/t/))
> **Update:** GitHub has [published more details about their plan](https://github.com/github/renaming) to move from `master` to `main` and it will indeed be voluntary and configurable. To my surprise, the Git maintainers have [also agreed to add](https://sfconservancy.org/news/2020/jun/23/gitbranchname/) a `init.defaultBranch` setting to customize the default branch for new repositories in Git 2.28.
But this means in the meantime, project owners are free to rename their branches as they please — and it's pretty simple to do so, usually with minimal disruption. [Some](https://github.com/desktop/desktop/issues/6478) [of](https://github.com/cli/cli/issues/929) [the](https://github.com/sindresorhus/awesome/issues/1793) [biggest](https://github.com/rust-lang/rustlings/issues/437) [OSS](https://github.com/twbs/bootstrap/pull/31050) [projects](https://github.com/ohmyzsh/ohmyzsh/issues/9015) have already voluntarily done so. Here's how to join them.
---
### 1. Move your `master` branch to `main`:
...or `development`, `unstable`, `trunk`, `live`, `original`; your choice!
We use `branch -m` to **move** the branch locally instead of creating a new one with `checkout -b` like you might be used to.
```bash
git branch -m master main
```
### 2. Push the new branch to GitHub:
The first command is probably familiar. `-u` sets the new branch as the local default at the same time, and the second line ensures our local `HEAD` points to our new branch on GitHub.
```bash
git push -u origin main
git remote set-head origin main
```
You can verify this worked by running `git branch -r`. You should see something like `origin/HEAD -> origin/main`.
### 3. Change the default branch in your repository's settings:
Setting the default branch remotely is the only step that can't be done on the command line (although you can technically [use the GitHub API](https://github.com/erbridge/github-branch-renamer)). Head to **Settings → Branches** on GitHub to [change the default branch](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/changing-the-base-branch-of-a-pull-request).
<img
className="center"
src="/static/images/notes/github-rename-master/github-default.png"
width="810"
height="405"
alt="Changing the default branch of a GitHub repository"
/>
### 4. Delete the old `master` branch on GitHub:
We used `-m` (move) to **rename** the `master` branch locally, but GitHub will still have two identical branches at this point (as you saw in the previous step). Deleting it can be a little nerve-racking, so poke around your repository on GitHub and make sure your new branch is there and the commit history is correct.
You can say good riddance to `master` [through the GitHub UI](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-and-deleting-branches-within-your-repository#deleting-a-branch) or with this command:
```bash
git push origin --delete master
```
### 5. Scan your code, scripts, automation, etc. for references to `master`:
Do a quick search of your codebase for `master` to manually replace any dead references to it.
Pay attention to CI files — `.travis.yml`, `.github/workflows/`, `.circleci/config.yml`, etc. — and make sure there aren't any external services relying on `master` being there. For example, I almost forgot to change the branch [Netlify triggers auto-deploys](https://docs.netlify.com/site-deploys/overview/#branches-and-deploys) from to build this site:
<img
className="center"
src="/static/images/notes/github-rename-master/netlify-deploy.png"
width="720"
height="460"
alt="Netlify auto-deployment branch setting"
/>
~~Unfortunately, GitHub won't redirect links containing `master` to the new branch (as of now), so look for any [github.com](https://github.com/) URLs as well.~~
> **Update:** GitHub is now [redirecting deleted branches](https://github.blog/changelog/2020-07-17-links-to-deleted-branches-now-redirect-to-the-default-branch/) to the default branch!
### Bonus points:
None of this will work on a brand new repository with zero commits. But we can hack around this limitation pretty easily...
You can create a [Git alias](https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases) in your local environment's `.gitconfig` to make `main` the default branch name for new repositories. Git doesn't let you override some native commands like `git init`, so we'll create our own `git new` command instead ([h/t @johnsyweb](https://twitter.com/johnsyweb/status/1269881549056438272)):
```bash
git config --global alias.new '!git init && git symbolic-ref HEAD refs/heads/main'
```
---
This may be a small gesture, but anything we can do to make even one more volunteer feel more welcome in the OSS community will _always_ be worth the extra 10 to 15 minutes of inconvenience on my end. ✊🏾
And while we're at it, Nat... **It's time to finally [#DropICE](https://github.com/drop-ice/dear-github-2.0).** 🧊
---
### Further reading:
- [_Master/slave (technology)_ on Wikipedia](<https://en.wikipedia.org/wiki/Master/slave_(technology)>)
- [History of "master" in BitKeeper → Git](https://mail.gnome.org/archives/desktop-devel-list/2019-May/msg00066.html)
- [More great research into context of "master/slave" in BitKeeper](https://twitter.com/jpaulreed/status/1272038656799211521)
- [Proposal to change "master" default on Git mailing list](https://lore.kernel.org/git/CAOAHyQwyXC1Z3v7BZAC+Bq6JBaM7FvBenA-1fcqeDV==apdWDg@mail.gmail.com/t/) (it did **not** go well...)
- [Django removes "master/slave" terminology (2014)](https://github.com/django/django/pull/2692)
- [Black Tech for Black Lives](https://www.blacktechforblacklives.com/)

View File

@ -0,0 +1,201 @@
---
title: "How To: Automatically Backup a Linux VPS to a Separate Cloud Storage Service"
date: 2019-06-09 19:03:10-0400
description: "A walkthrough for backing up a Linux server to an external storage provider like Amazon S3 automatically."
tags:
- How To
- Tutorial
- Servers
- Backups
- Linux
- Restic
image: "/static/images/notes/how-to-backup-linux-server/apocalypse.png"
---
<figure>
<img
src="/static/images/notes/how-to-backup-linux-server/apocalypse.png"
width="865"
height="303"
alt="The Cloud-pocalypse: Coming soon(er than you think) to a server near you."
/>
<figcaption>
<strong>The Cloud-pocalypse:</strong> Coming soon(er than you think) to a server near you.
</figcaption>
</figure>
Last month, the founder of [a small startup](https://raisup.com/) got quite a bit of [attention on Twitter](https://twitter.com/w3Nicolas/status/1134529316904153089) (and [Hacker News](https://news.ycombinator.com/item?id=20064169)) when he called out [DigitalOcean](https://www.digitalocean.com/) who, in his words, "killed" his company. Long story short: DigitalOcean's automated abuse system flagged the startup's account after they spun up about ten powerful droplets for some CPU-intensive jobs and deleted them shortly after — which is literally **the biggest selling point** of a "servers by the hour" company like DigitalOcean, by the way — and, after replying to the support ticket, an unsympathetic customer support agent [declined to reactivate](https://twitter.com/w3Nicolas/status/1134529372172509184) the account without explanation. [Nicolas](https://twitter.com/w3Nicolas) had no way of even accessing his data, turning the inconvenient but trivial task of migrating servers into a potentially fatal situation for his company.
<tweet id="1134529316904153089" />
Predictably, there were [a](https://twitter.com/kolaente/status/1134897543643615238) [lot](https://twitter.com/hwkfr/status/1135164281731911681) [of](https://twitter.com/joestarstuff/status/1135406188114276352) [Monday](https://twitter.com/FearbySoftware/status/1134717875351052288)-[morning](https://twitter.com/mkozak/status/1134557954785587200) [quarterbacks](https://twitter.com/MichMich/status/1134547174447026181) who weighed in, scolding him for not having backups ([he did](https://twitter.com/w3Nicolas/status/1134529374676500482), but they were also stored on DigitalOcean) and not paying a boatload of non-existent money for expensive load balancers pointing to multiple cloud providers. Hindsight is always 20/20, of course, but if we're talking about a small side project that exploded into a full-fledged startup with Fortune 500 clients seemingly overnight, I _completely_ understand Nicolas' thought process. _"Let's just take advantage of cloud computing's #1 selling point: press a few buttons to make our servers [harder, better, faster, stronger](https://www.youtube.com/watch?v=x84m3YyO2oU) and get back to coding!"_
Most of the popular one-click server providers (including [DigitalOcean](https://www.digitalocean.com/docs/images/backups/overview/), as well as [Linode](https://www.linode.com/backups), [Vultr](https://www.vultr.com/docs/vps-automatic-backups), and [OVH](https://www.ovh.com/world/vps/backup-vps.xml)) provide their own backup offerings for an additional monthly cost (usually proportional to your plan). But as Nicolas learned the hard way, any amount of backups are just more eggs in the same basket if everything is under one account with one credit card on one provider.
Luckily, crafting a DIY automated backup system using a second redundant storage provider isn't as daunting (nor as expensive) as it might sound. The following steps are how I backup my various VPSes to a totally separate cloud in the sky.
---
There are quite a few tools that have been around for decades that could accomplish this task — namely [`rsync`](https://en.wikipedia.org/wiki/Rsync) — but an [open-source](https://github.com/restic/restic) tool named [**Restic**](https://restic.net/) has won my heart for both its simplicity and the wide range of destinations it natively supports, including but not limited to:
- [Amazon AWS S3](https://aws.amazon.com/s3/)
- [Backblaze B2](https://www.backblaze.com/b2/cloud-storage.html)
- [Google Cloud Storage](https://cloud.google.com/storage/)
- [Azure Storage](https://azure.microsoft.com/en-us/services/storage/)
- ...and [literally anywhere](https://restic.readthedocs.io/en/stable/030_preparing_a_new_repo.html#sftp) you can SFTP (or SSH) into.
Backups are encrypted by default, too, which is a tasty cherry on top!
Setting up Restic is certainly easier than a low-level tool like `rsync`, but it can still be tricky. Follow these steps and you'll have a fully automated system making easily restorable backups of your important files in preparation for your own (likely inevitable) Cloud-pocalypse.
---
## 0. Sign up for a second cloud service
I host most of my projects on [Linode](https://www.linode.com/?r=0c5aeace9bd591be9fbf32f96f58470295f1ee05) (affiliate link) and chose [Amazon's S3](https://aws.amazon.com/s3/) as my backup destination. S3 is easily the gold-standard in random file storage and I'd highly recommend it — unless your servers are also on Amazon with EC2, of course. My second choice would be [Backblaze's B2](https://www.backblaze.com/b2/cloud-storage.html), which is comparable to S3 in semantics and price.
Writing steps to create an S3 bucket would be incredibly redundant, so here are Amazon's writeups on creating one (make sure the bucket is **_fully private;_** the other default settings are fine) as well as grabbing your account's "access keys" which will be used to authenticate Restic with S3.
- [How Do I Create an S3 Bucket?](https://docs.aws.amazon.com/quickstarts/latest/s3backup/step-1-create-bucket.html)
- [Understanding and Getting Your Security Credentials](https://docs.aws.amazon.com/general/latest/gr/managing-aws-access-keys.html)
## 1. Install Restic
Restic might be included in your OS's default repositories (it is on Ubuntu) but it's better to opt for the releases on [Restic's GitHub page](https://github.com/restic/restic/releases). The binary you'll get from `apt` or `yum` will be several versions behind, and the GitHub flavor auto-updates itself anyways.
Find the latest version of Restic on their [GitHub releases page](https://github.com/restic/restic/releases/latest). Since I'm assuming this is a Linux server, we only want the file ending in `_linux_amd64.bz2`. (For a 32-bit Linux server, find `_linux_386.bz2`. Windows, macOS, and BSD binaries are also there.) Right-click and copy the direct URL for that file and head over to your server's command line to download it into your home directory:
```bash {linenos=false}
cd ~
wget https://github.com/restic/restic/releases/download/v0.9.5/restic_0.9.5_linux_amd64.bz2
```
Next, we'll unzip the download in place:
```bash {linenos=false}
bunzip2 restic_*
```
This should leave us with a single file: the Restic binary. In order to make Restic available system-wide and accessible with a simple `restic` command, we need to move it into the `/usr/local/bin` folder, which requires `sudo` access:
```bash {linenos=false}
sudo mv restic_* /usr/local/bin/restic
sudo chmod a+x /usr/local/bin/restic
```
Now's a good time to run `restic` to make sure we're good to move on. If you see the version number we downloaded, you're all set!
```bash {linenos=false}
restic version
```
## 2. Connect Restic to S3
This step is a _little_ different for each cloud provider. My walkthrough assumes S3, but [Restic's documentation](https://restic.readthedocs.io/en/latest/030_preparing_a_new_repo.html) lays out the variables you'll need to authenticate with different providers.
If you haven't already [created a new S3 bucket](https://docs.aws.amazon.com/quickstarts/latest/s3backup/step-1-create-bucket.html) and grabbed your [access key and secret](https://docs.aws.amazon.com/general/latest/gr/managing-aws-access-keys.html) from the AWS console, do so now.
We need to store these keys as environment variables named `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`. For now, we'll set these temporarily until we automate everything in the next step.
```bash {linenos=false}
export AWS_ACCESS_KEY_ID="your AWS access key"
export AWS_SECRET_ACCESS_KEY="your AWS secret"
```
We'll also need to tell Restic where the bucket is located and set a secure password to encrypt the backups. You can generate a super-secure 32-character password by running `openssl rand -base64 32` — just make sure you store it somewhere safe!
```bash {linenos=false}
export RESTIC_REPOSITORY="s3:s3.amazonaws.com/your-bucket-name"
export RESTIC_PASSWORD="passw0rd123-just-kidding"
```
## 3. Initialize the backup repository
Now we're ready to have Restic initialize the repository. This saves a `config` file in your S3 bucket and starts the encryption process right off the bat. You only need to run this once.
```bash {linenos=false}
restic init
```
If successful, you should see a message containing `created restic backend`. If not, make sure you set all four environment variables correctly and try again.
## 4. Make our first backup
Now that the hard parts are done, creating a backup (or "snapshot" in Restic terms) is as simple as a one-line command. All we need to specify is the directory you want to backup.
```bash {linenos=false}
restic backup /srv/important/data
```
Running `restic snapshots` will list every snapshot you've stored. You should see one listed at this point if everything went according to plan.
## 5. Automate backups using a cron job
All of this is fine and good, but doing this manually whenever you happen to remember to won't be very helpful if trouble strikes. Thankfully, Linux makes it incredibly easy to automate scripts using [cron jobs](https://en.wikipedia.org/wiki/Cron). So let's set one up for this.
Make a new file at a convenient location on your server and name it `backup.sh`. This is where we'll replicate everything we did above. Here's my full `.sh` file:
```bash
#!/bin/bash
export AWS_ACCESS_KEY_ID="xxxxxxxx"
export AWS_SECRET_ACCESS_KEY="xxxxxxxx"
export RESTIC_REPOSITORY="s3:s3.amazonaws.com/xxxxxxxx"
export RESTIC_PASSWORD="xxxxxxxx"
restic backup -q /srv/xxxxxxxx
```
(The `-q` flag silences the output, since we won't be able to see it anyways.)
I highly recommend adding one final command to the end of the file: Restic's `forget` feature. Constantly storing multiple snapshots a day to S3 without pruning them will rack up your bill more than you'd probably like. Using `forget`, we can specify how many snapshots we want to keep and from when.
This command keeps one snapshot from each of the last **six hours**, one snapshot from each of the last **seven days**, one snapshot from each of the last **four weeks**, and one snapshot from each of the last **twelve months**.
```bash {linenos=false}
restic forget -q --prune --keep-hourly 6 --keep-daily 7 --keep-weekly 4 --keep-monthly 12
```
Reading [the documentation](https://restic.readthedocs.io/en/latest/060_forget.html#removing-snapshots-according-to-a-policy) for different `forget` options can be helpful if you want to customize these.
Save the shell script and close the editor. Don't forget to make the script we just wrote actually executable:
```bash {linenos=false}
chmod +x backup.sh
```
Lastly, we need to set the actual cron job. To do this, run `sudo crontab -e` and add the following line to the end:
```bash {linenos=false}
0 * * * * /root/backup.sh
```
The first part specifies how often the script should run. `0 * * * *` runs it right at the top of every hour. Personally, I choose to run it at the 15th minute of every _other_ hour, so mine looks like `15 */2 * * *`. [crontab.guru](https://crontab.guru/#0_*_*_*_*) is a nifty "calculator" to help you customize this expression to your liking — it's definitely not the most intuitive syntax.
The second part specifies where the script we just wrote is located, of course, so set that to wherever you saved `backup.sh`.
## 6. Verifying and restoring snapshots
**Side note:** In order to use `restic` in future shell sessions, we need to make the four environment variables permanent by adding them to your `.bash_profile` or `.bashrc` file in your home directory. Simply copy and paste the four `export` lines from the `backup.sh` file we created above to the end of either dotfile.
Take note of the next time that your new cron job _should_ run, so we can check that it was automatically triggered. After that time — at the top of the next hour if you used my defaults in the last step — you can run `restic snapshots` like we did before to make sure there's an additional snapshot listed, and optionally take the IDs of each snapshot and run `restic diff ID_1 ID_2` to see what's changed between the two.
To restore a snapshot to a certain location, grab the ID from `restic snapshots` and use `restore` like so:
```bash {linenos=false}
restic restore 420x69abc --target ~/restored_files
```
You can also replace the ID with `latest` to restore the latest snapshot.
~~If~~ When trouble strikes and you're setting up a new server, just re-follow steps one, two, and six and you'll have all your files back before you know it!
There are a few other neat options for browsing and restoring snapshots, like `mount`ing a snapshot as a disk on your file system. Read more about that on the ["restoring from backup" docs](https://restic.readthedocs.io/en/latest/050_restore.html) page.
---
Again, [Restic's documentation](https://restic.readthedocs.io/en/latest/index.html) is really, really well written, so I definitely recommend skimming it to see what else is possible.
Literally every company's Doomsday protocols can _always_ be improved, and external backups are just one part of redundancy. But pat yourself on the back — this might have been a convoluted process, but hopefully you'll be able to sleep better at night knowing your startup or personal server now has a **far** better chance of surviving whatever the cloud rains down upon you!
If you have any questions, feel free to leave a comment or [get in touch with me](https://twitter.com/jakejarvis). Be safe out there!

View File

@ -0,0 +1,125 @@
---
title: "How To: Fork a GitHub Repository & Submit a Pull Request"
date: 2019-04-09 02:17:03-0400
description: "Walkthrough of forking a GitHub repository, cloning it, commiting your changes to a new branch, and pushing it back upstream."
tags:
- How To
- Tutorial
- Git
- Pull Request
- Open Source
- GitHub
image: "/static/images/notes/how-to-pull-request-fork-github/step7-2.png"
---
<svg width="150" height="150" viewBox="0 0 40 40" style={{ float: "right", marginBottom: "6px", marginLeft: "12px" }}>
<path d="M6.5 35v-4.8c0-5.4 4.3-9.7 9.7-9.7h7.6c5.4 0 9.7-4.3 9.7-9.7V6M6.5 32.5v-26" fill="none" stroke="#a3b7cc" />
<path d="M6.5 10.5a4 4 0 110-8 4 4 0 010 8z" fill="#8bb7f0" />
<path d="M6.5 3a3.5 3.5 0 110 7 3.5 3.5 0 010-7m0-1a4.5 4.5 0 100 9 4.5 4.5 0 000-9z" fill="#4e7ab5" />
<path d="M33.5 10.5a4 4 0 110-8 4 4 0 010 8z" fill="#8bb7f0" />
<path d="M33.5 3a3.5 3.5 0 110 7 3.5 3.5 0 010-7m0-1a4.5 4.5 0 100 9 4.5 4.5 0 000-9z" fill="#4e7ab5" />
<g>
<path d="M6.5 37.5a4 4 0 110-8 4 4 0 010 8z" fill="#8bb7f0" />
<path d="M6.5 30a3.5 3.5 0 110 7 3.5 3.5 0 010-7m0-1a4.5 4.5 0 100 9 4.5 4.5 0 000-9z" fill="#4e7ab5" />
</g>
</svg>
Contributing to an open-source project can be intimidating at first. The convoluted process of submitting your improvements for approval via a [**pull request**](https://help.github.com/en/articles/about-pull-requests) certainly doesn't help.
The following steps to submit a pull request will work on Git repositories hosted anywhere — on [GitLab](https://gitlab.com/), [Bitbucket](https://bitbucket.org/), [Azure DevOps](https://azure.microsoft.com/en-us/services/devops/repos/), etc. — but most open-source repositories one would want to contribute to are likely on [**GitHub**](https://github.com/), which is what we'll be using.
Starting from the very beginning, we'll fork an existing repository to our account, clone the fork locally, commit your changes to a new branch, and push it back upstream to GitHub to submit for approval.
## 1. Forking the Repository
Assuming you're using GitHub, this step is easy. Just find the repository you're contributing to and press the Fork button in the upper left. This will create an exact copy of the repository (and all of its branches) under your own username.
<img
className="center"
src="/static/images/notes/how-to-pull-request-fork-github/step1.png"
width="865"
height="80"
alt="Step 1"
/>
## 2. Clone your new fork locally
GitHub will automatically redirect you to the forked repository under your username. This is the repository you need to clone to your local development environment, **not** the original. Grab the URL GitHub provides under the green "Clone or Download" button and plug it into the command below.
```bash
git clone git@github.com:jakejarvis/react-native.git
```
<img
className="center"
src="/static/images/notes/how-to-pull-request-fork-github/step2.png"
width="420"
height="208"
alt="Step 2"
/>
## 3. Track the original repository as a remote of the fork
_This step is technically optional, but important if you plan to continue contributing to a project in the future, so we might as well..._
Once you've forked a repository, changes to the original (or "upstream") repository are not pushed to your fork. We need to tell the new repository to follow changes made upstream to keep it fresh via [remotes](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes).
Switch directories to the forked repository you just cloned and run the following commands. Replace the last part of the first line with the **original** repository clone URL — similar to the how you grabbed the URL in step 2, but this **isn't** the one with your username.
This links the fork back to the original repository as a remote, which we'll name `upstream`, and then fetch it.
```bash
git remote add --track master upstream git@github.com:facebook/react-native.git
git fetch upstream
```
## 4. Create a new branch for your changes
It's possible to make changes directly to the `master` branch, but this might FUBAR things down the road for complicated reasons. It's best to [`checkout`](https://git-scm.com/docs/git-checkout) a new branch for **each** change/improvement you want to make. Replace `fix-readme-typo` with a more descriptive name for your changes, like `add-mobile-site` or `update-dependencies`.
```bash
git checkout -b fix-readme-typo upstream/master
```
## 5. Make your changes!
This is either the easiest part or the hardest part, depending on how you look at it. 😉 At this point, you're isolated in the new branch you just created, and it's safe to open whatever text editor or IDE you use and go wild.
## 6. Add, commit, and push the changes
You're probably used to these commands. Add the files you've changed and commit them with a descriptive message.
```bash
git add .
git commit -m "Fix grammar mistakes in the readme file"
```
The one difference is the branch you're pushing to. You likely usually push to `master`, but in this case, we're pushing to the branch with the name you created in step 4.
```bash
git push -u origin fix-readme-typo
```
## 7. Submit your pull request
You're now all ready to submit the improvement you've made to the project's maintainers for approval. Head over to the original repositories Pull Requests tab, and you should see an automatic suggestion from GitHub to create a pull request from your new branch.
<img
className="center"
src="/static/images/notes/how-to-pull-request-fork-github/step7-1.png"
width="865"
height="75"
alt="Step 7.1"
/>
<img
className="center"
src="/static/images/notes/how-to-pull-request-fork-github/step7-2.png"
width="700"
height="354"
alt="Step 7.2"
/>
---
I'll admit, I need to refer back to these notes sometimes when I'm preparing to contribute to an open-source project. It's certainly not the most [intuitive](https://ohshitgit.com/) process, but at least it's **exactly the same** wherever the project is located — for example, I host my own [small Gitea server](https://code.jarv.is/) to back up some of my GitHub account. This instant compatibility between completely different services is precisely what makes Git great! 🏆

View File

@ -0,0 +1,118 @@
---
title: "How To: Shrink a Linux Virtual Machine Disk with VMware"
date: 2018-12-04 19:10:04-0400
description: "VMware is bad at shrinking Linux VMs when space is freed up. How to optimize and shrink virtual disks."
tags:
- How To
- Linux
- Tutorial
- Virtual Machines
- VMware
image: "/static/images/notes/how-to-shrink-linux-virtual-disk-vmware/screen-shot-2018-12-07-at-2-04-04-pm.png"
---
<figure>
<img
src="/static/images/notes/how-to-shrink-linux-virtual-disk-vmware/screen-shot-2018-12-07-at-2-04-04-pm.png"
width="620"
height="456"
alt="df -dh = WTF"
/>
<figcaption>
<code>df -dh</code> = WTF
</figcaption>
</figure>
**[VMware Workstation](https://www.vmware.com/products/workstation-pro.html)** and **[Fusion](https://www.vmware.com/products/fusion.html)** normally work hard to minimize the size of virtual hard disks for optimizing the amount of storage needed on your host machine . On Windows virtual machines, [VMware has a "clean up" function](https://docs.vmware.com/en/VMware-Fusion/11/com.vmware.fusion.using.doc/GUID-6BB29187-F47F-41D1-AD92-1754036DACD9.html), which detects newly unused space and makes the size of the virtual hard disk smaller accordingly. You'll notice that even if you create a virtual machine with a capacity of 60 GB, for example, the actual size of the VMDK file will dynamically resize to fit the usage of the guest operating system. 60 GB is simply the maximum amount of storage allowed; if your guest operating system and its files amount to 20 GB, the VMDK file will simply be 20 GB.
VMware can be set to automatically optimize and shrink virtual hard disks as you add and, more importantly, remove files — but [this automatic "clean up" setting is disabled by default](https://docs.vmware.com/en/VMware-Fusion/11/com.vmware.fusion.using.doc/GUID-6BB29187-F47F-41D1-AD92-1754036DACD9.html). Either way, cleaning up virtual machines works like a charm...when you have Windows as a guest operating system with an NTFS disk.
As a developer, I have several VMs with various Linux-based guest OSes — and, for some reason, VMware doesn't know how to optimize these. If you poke around in VMware, you'll find that the clean up button is greyed-out under the settings of a Linux VM.
Commonly, I'll use a few gigabytes of storage for a project and then delete the files from the guest when I'm done. Let's say that my Debian guest starts at 10 GB and I use 5 GB for my project, totaling 15 GB. The VMDK file will be, obviously, 15 GB. I finish the project and delete the 5 GB of its files. On a Windows guest, VMware would be able to shrink the volume back down to 10 GB — but you'll quickly notice, annoyingly, that a Linux disk will remain at 15 GB, even though you're no longer using that much. On a portable machine like my MacBook Air, this can be a _huge_ waste!
The "clean up" feature that VMware has developed for Windows guests can be applied to Linux guests as well, but it's pretty convoluted — we need to essentially clean up the VM ourselves, trick VMware to detect the free space, and manually shrink the volume.
**_A tiny caveat:_** This only works on VMs without any snapshots. Sadly, you either need to delete them or, if you care about keeping snapshots, you can backup the VM as-is to an external disk and then delete the local snapshots.
Once you're ready, here's how to shrink your Linux-based VM:
---
### Update (Dec. 30, 2018):
The open-source version of VMware Tools for Linux, [open-vm-tools](https://github.com/vmware/open-vm-tools), has added a simple command to automate the above steps in the latest version. Make sure you have the latest update through either apt or yum, and then run the following command in the **guest** terminal:
```bash
vmware-toolbox-cmd disk shrink /
```
Thank you to [commenter Susanna](https://jake.wordpress.com/2018/12/04/how-to-shrink-linux-virtual-disk-vmware/#comment-21) for pointing this out! The manual way below still works exactly the same.
---
## Step 1: Clean up time
Boot up your Linux virtual machine. We'll start by optimizing the OS as much as possible before shrinking it. In addition to manually deleting files you no longer use, running this command in your terminal can free up a little more space by removing some installation caches left behind by old versions of software you've installed and updated:
```bash
sudo apt-get clean
```
## Step 2: Make "empty" space actually empty
This step is the crucial one. In order for VMware to detect the newly free space, we need to free it up ourselves using a little trickery. We're going to have Linux overwrite the free space with a file full of zeros — the size of this file will be the size of however much space we're freeing up (5 GB, in the example above) — and then delete it. These commands will create the file, wait a moment, and then delete the file:
```bash
cat /dev/zero > zero.fill
sync
sleep 1
sync
rm -f zero.fill
```
Depending on how much space we're freeing, this could take a while. Let it finish or else you'll be left with an actual, real file that will occupy a ton of space — the opposite of what we're trying to accomplish!
## Step 3: Letting VMware know we've done its dirty work
The final step is to tell VMware we've done this, and manually trigger the clean up function that works so well on Windows VMs. You'll do this step **outside** of the virtual machine, so shut it down fully and exit VMware. These directions are for macOS hosts specifically — if you're on a Linux host, I'll assume you are able to find the VMDK file, but [here's some help if you need](https://www.howtogeek.com/112674/how-to-find-files-and-folders-in-linux-using-the-command-line/).
VMware on macOS makes this a little tricky, since it packages VMs in what looks like a ".vmwarevm" file, which is actually a folder. Browse to wherever you've saved your virtual machines, probably somewhere in your home folder, and find the location of this ".vmwarevm" androgynous item. If you click on this folder, though, it'll just open VMware again.
We need to right click on the .vmwarevm "file," and select **Show Package Contents** to see what's really in there. You should see the actual .VMDK file sitting there — normally we're looking for the plain VMDK file (named _Virtual Disk.vmdk_ by default) without a bunch of numbers after it, but if you have snapshots associated with your VM, this might not be the file we actually want. But run the command below with it anyways, and the output will tell you if you need to use a different file.
<img
className="center"
src="/static/images/notes/how-to-shrink-linux-virtual-disk-vmware/screen-shot-2018-12-07-at-1-58-42-pm.png"
width="680"
height="572"
alt="Finding .vmwarevm in Finder"
/>
Now, we're going to run our final command in our **host** terminal, so open that up. Linux installations of VMware Workstation should have a simple map to the _vmware-vdiskmanager_ utility that you can run anywhere, but on macOS we need to tell it exactly where that's located: in the Applications folder, where Fusion is installed.
We're going to feed this command the exact location of the VMDK file we're shrinking. You can either do this by typing the **full path** to it, or by simply dragging the VMDK file onto the terminal after typing the first part of the command (up to and including "-d"). The "-d" argument will defragment the disk.
```bash
/Applications/VMware\ Fusion.app/Contents/Library/vmware-vdiskmanager -d <path to your .VMDK file>
```
The final command should look something like this, with your VMDK file instead:
```bash
/Applications/VMware\ Fusion.app/Contents/Library/vmware-vdiskmanager -d /Users/jake/Documents/Virtual\ Machines/Debian9.vmwarevm/Virtual\ Disk.vmdk
```
If you've done this correctly, you'll see it defragmenting the file, and then return "Defragmentation completed successfully." If it returns a different error, such as "This disk is read-only in the snapshot chain," it should tell you which disk you should actually shrink. Just run the command again with that VMDK file instead.
After the defragmentation completes, we need to finally shrink the image. We do this by running the same command as you did above, but replacing the "-d" with "-k" as follows:
```bash
/Applications/VMware\ Fusion.app/Contents/Library/vmware-vdiskmanager -k <path to the same .VMDK file>
```
## Step 4: Storage Profit!
Obviously, this is a really annoying way to perform a feature that only takes one click to execute on Windows virtual machines. I don't recommend going through this entire process every time you delete a few random files. However, if you notice the free space on your host OS is mysteriously lower than it should be, the time this takes can be well worth it.
Let's hope this will be integrated in VMware Tools in the near future — feel free to [nudge VMware about it](https://my.vmware.com/group/vmware/get-help?p_p_id=getHelp_WAR_itsupport&p_p_lifecycle=0&_getHelp_WAR_itsupport_execution=e1s2) in the meantime!

View File

@ -0,0 +1,99 @@
---
title: "Why This Millennial Is With Hillary Clinton Now — and Why We All Need To Be In November"
date: 2016-02-29 00:10:26-0400
description: 'I am a 24-year-old "millennial" and I passionately support Hillary Clinton for the 45th President of the United States. Yes, we exist.'
tags:
- 2016 Presidential Election
- Bernie Sanders
- Hillary Clinton
- Politics
image: "/static/images/notes/millenial-with-hillary-clinton/24707394571_0818d4ab83_o-1-copy.jpg"
---
<figure>
<img
src="/static/images/notes/millenial-with-hillary-clinton/24707394571_0818d4ab83_o-1-copy.jpg"
width="865"
height="411"
alt="Hillary for New Hampshire Winter Fellows with Hillary Clinton in Derry, NH (February 3, 2016)"
/>
<figcaption>
<a href="https://medium.com/@HillaryForNH" target="_blank" rel="noopener noreferrer">
Hillary for New Hampshire
</a>{" "}
Winter Fellows with{" "}
<a href="https://medium.com/@HillaryClinton" target="_blank" rel="noopener noreferrer">
Hillary Clinton
</a>{" "}
in Derry, NH (
<a href="https://www.flickr.com/photos/hillaryclinton/24707394571/" target="_blank" rel="noopener noreferrer">
February 3, 2016
</a>
)
</figcaption>
</figure>
## Keeping in mind the big picture...
I am a 24-year-old "millennial" and I passionately support [Hillary Clinton](https://www.hillaryclinton.com/) for the 45th President of the United States. Yes, we exist.
My goal here isn't to convince every Bernie believer to jump ship and support her as passionately as I do, although I feel obligated to try. I totally understand the passion for Bernie. I smile inside every time I see a young person (like my sister) become interested in politics for the first time and become directly involved in influencing the course of their own future, no matter which candidate triggered it for them. For me, it was admittedly Senator Obama. I would, however, like to put the Democratic Party primary process back into perspective, because it's turned into a bloodsport that isn't helpful for _anybody_ in the long run — not for either candidate, not for our party, and certainly not for our country.
**News Flash:** We aren't in the general election right now. Not even close. We're in the middle of _our own party's_ primary, where the field of opponents we are choosing from are all our friends. They're both on our side. They both agree on an overall vision for our country. Of course as individuals we choose one who we like better than the other, and root for her or him and ideally invest some time and money to help however we can. I chose Hillary a long time ago because I feel she is, if anything, overqualified for the position. Especially during this increasingly turbulent period of foreign affairs, we can't afford to allow an entry-level applicant to experiment with our standing in the world and learn our relationships with other nations on-the-fly.
After working for months as a fellow on Hillary's campaign in New Hampshire leading up to the first primary in the country, I could feed you all the standard campaign talking points in my sleep: After graduating from Yale Law she went to work at the [Children's Defense Fund](https://www.childrensdefense.org/), not a high-paying New York law firm. She [went undercover](https://www.nytimes.com/2015/12/28/us/politics/how-hillary-clinton-went-undercover-to-examine-race-in-education.html?_r=0) in Alabama to investigate discrimination in public schools. She [got juveniles out of adult prisons](https://www.huffingtonpost.com/entry/huffpost-criminal-justice-survey-democratics_us_56bb85eae4b0b40245c5038b). She [gave 8 million children healthcare](https://www.hillaryclinton.com/briefing/factsheets/2015/12/23/hillary-clintons-lifelong-fight-for-quality-affordable-health-care-for-all-americans/). But there's just one thing that, for some reason, is hard for people to believe: at her core she is a good, caring, and loving person who has had only selfless intentions her entire life. I promise you.
<figure>
<img
src="/static/images/notes/millenial-with-hillary-clinton/9e58a-1bvweqv_ve2_c1tw5-ihrhw.jpg"
width="400"
height="500"
alt="The best birthday gift. 🎉"
/>
<figcaption>The best birthday gift. 🎉</figcaption>
</figure>
I had the incredible chance to meet Hillary the weekend before the New Hampshire primary. Her motorcade plowed through a quiet suburb in Manchester around noon and she hopped out to go knock on the doors of some lucky families. As neighbors started coming out of their houses to shake her hand, I couldn't restrain myself from at least trying to get close and wave hello. (By the way, it's amazing how casual the people in New Hampshire are about meeting presidential candidates.)
I walked up nervously and told her that it was my birthday (it was) and all I wanted was for her to win, which got her attention, and I thanked her for the spotlight she had been shining on the rampant addiction epidemic in the state. Instead of nodding her head and thanking me for my support and moving along like I assumed she would — she knew she would have my vote no matter what — she locked eyes with me and asked me how I'd been affected by the issue. It felt as though she dropped everything in her life and literally put her jam-packed schedule on pause to make sure I was okay and to learn more about some dude she just met ten seconds ago. I told her that I had fallen into the trap myself when I was younger, and that the [part of her detailed plan](https://www.hillaryclinton.com/issues/addiction/) that addresses the overprescription of narcotics by doctors could have prevented me from doing so. As my conversation with her grew longer and longer, and as she respectfully asked me more and more questions about my story, I totally forgot I was casually chatting on the sidewalk with a freaking former First Lady, Senator, and Secretary of State. I promise you again: She. Is. A. Real. Person.
> "I know I have some work to do, particularly with young people, but I will repeat again what I have said this week. Even if they are not supporting me now, I support them." [»](https://www.vox.com/2016/2/9/10956458/hillary-clinton-new-hampshire)
But at the end of the day, all I ask is for you to keep in mind the stakes in this overall election. They have never been higher. Last year, the spectacle of Donald "The Donald" Trump running to be the leader of the free world was purely comical and impossible not to laugh at, from the moment he entered the race [via gold-plated escalator](https://www.youtube.com/watch?v=Ab9AnZaLL1U) whilst blasting Neil Young. But as this racist xenophobic pumpkin is rapidly racking up _actual real-life delegates_ thanks to votes from the [poorly educated](https://www.vox.com/2016/2/24/11107788/donald-trump-poorly-educated) and/or the [white supremacists](https://www.huffingtonpost.com/entry/donald-trump-white-supremacist-sec-primary_us_56cf4437e4b0bf0dab31222f), the thought of him being within striking distance of the desk in the Oval Office is slowly twisting a knife into the pit of my stomach. This is real. This is the big picture. This is why we need to team up and work together in any way possible as soon as possible.
I'm aware of the street cred young Democrats collect by claiming they hated Hillary before hating Hillary was cool. Hating on HRC has gone more viral than Damn Daniel. But when you ask these young voters to explain why they think she's a liar or untrustworthy or a criminal, they can rarely put their distaste for her into actual words — or if they do, they just vomit hashtag-ready soundbites from Fox News or The Young Turks. #Benghazi. #Emails. #ReleaseTheTranscripts. Joining in on the Republican-led attacks and stooping to their level is no way to advocate for the candidate you support. If you support Bernie for the nomination, you do that by going out and talking to others about why **his** policies rock, what **his** life story is, how **your** story relates to **his** story and **his** policies, etc. — not by spending your day mercilessly assassinating the character of a woman you've never met and a woman you might very well be voting for in eight short months, unless you're able to stomach the idea of President Trump. During primary season, you win by focusing on the merits of your own candidate, not the flaws you see in another.
As [Bill Maher](https://medium.com/u/cdc04a9799f6) (an avid Bernie supporter) [said this weekend](https://www.youtube.com/watch?v=rd1gpjkjcfc), some in our party need to "learn the difference between an imperfect friend and a deadly enemy." I don't agree with everything Hillary has said or done. I don't unconditionally defend every single chapter in her public record over the past 30 years (and [neither does she](https://www.washingtonpost.com/blogs/post-partisan/wp/2016/02/25/hillary-clinton-responds-to-activist-who-demanded-apology-for-superpredator-remarks/), by the way). I don't think that's possible for any voter to find in a politician. But if you identify as a Democrat, she is the farthest thing from your enemy. Plain and simple. Like you and Bernie, she wants to prevent a Republican from winning in November and reversing so much of the progress we've made over the past seven years on their first day in office. That is our number one goal right now. And whether it gets accomplished by a President Clinton or a President Sanders, I am 100% on board either way. Let's stop fighting each other and start fighting together.
<video url="https://www.youtube-nocookie.com/watch?v=TqrwDMTByNM" controls />
---
**Update:** The campaign has included my snowy New Hampshire interaction with her in one of the DNC convention videos! See a few short seconds of my joy at 1:24.
<video
url={[
{ src: "/static/images/hillary/convention-720p.webm", type: "video/webm" },
{ src: "/static/images/hillary/convention-720p.mp4", type: "video/mp4" },
]}
config={{
file: {
attributes: {
poster: "/static/images/hillary/thumb.png",
controlsList: "nodownload",
preload: "metadata",
autoPlay: false,
},
tracks: [
{
kind: "subtitles",
src: "/static/images/hillary/subs.en.vtt",
srcLang: "en",
label: "English",
default: true,
},
],
},
}}
controls={true}
/>

195
notes/my-first-code.mdx Normal file
View File

@ -0,0 +1,195 @@
---
title: "My First Code: Jake's Bulletin Board"
date: 2019-10-01 08:34:25-0400
description: "My first full coding project ever: a PHP bulletin board creatively titled Jake's Bulletin Board, circa 2003."
tags:
- Hello World
- Baby's First PHP
- Nostalgia
- Vintage Code
- Awesome List
image: "/static/images/notes/my-first-code/jbb-screen1.png"
---
<img
src="/static/images/notes/my-first-code/netscape.png"
width="865"
height="155"
alt="Awesome First Code on GitHub"
/>
<img
className="center"
src="/static/images/notes/my-first-code/badges.png"
width="537"
height="36"
alt="Code Quality: A for effort"
/>
I recently published my terrible, horrible, no good, very bad [first HTML site](https://jakejarvis.github.io/my-first-website/) and [first PHP project](https://github.com/jakejarvis/jbb#readme) ever and developed a new addiction to Web 1.0 nostalgia, fed by others who were brave enough to do the same.
So, I started compiling an [awesome-list of other "first code" on GitHub](https://github.com/jakejarvis/awesome-first-code). It was originally aimed towards those of us who grew up in the Geocities and FrontPage and Macromedia Flash era, but coders of all ages are welcome to dust off that floppy disk or 256MB USB thumb drive (or the [Wayback Machine](https://archive.org/web/), if you can remember your first screen name 😬) and commit your first project unmodified to GitHub for posterity — and proudly [link to it](https://github.com/jakejarvis/awesome-first-code/edit/master/readme.md) on the list! (I'm trying very hard to make this a cool trend, if you couldn't tell.)
Hopefully we can all look back at our first projects and be proud of how far we've come since then — no embarrassment allowed! Okay, maybe a little is fine...
---
<figure>
<a class="no-underline" href="https://github.com/jakejarvis/jbb" target="_blank" rel="noopener noreferrer">
<img src="/static/images/notes/my-first-code/jbb-logo.png" width="640" height="80" alt="Jake's Bulletin Board" />
</a>
<figcaption>
<a href="https://github.com/jakejarvis/jbb" target="_blank" rel="noopener noreferrer">
Jake's Bulletin Board
</a>
</figcaption>
</figure>
Aside from my [first HTML creation](https://jakejarvis.github.io/my-first-website/) (circa 2001), my first real coding project was in 2003: a PHP 4 masterpiece creatively titled **Jake's Bulletin Board**. I've published the [source code in full on GitHub](https://github.com/jakejarvis/jbb) for your viewing pleasure and highlighted the best/worst parts below.
## Usage
If you're bored on a rainy day, potential activities could include:
- Easiest code review you'll do in your entire career. (Or hardest, depending on your attitude.)
- Hacking speed-runs to boost your infosec self-esteem.
- Beating the [world record for longest laugh](http://goldenbookofrecords.com/longest-laughter/), currently held by Mr. Belachew Girma of Ethiopia with 3 hours and 6 minutes.
- Actually getting this to run in 2019.
## Embarrassing Highlights
Who cares if somebody wants to delete a post with the ID "`*`" no matter the author? ([delete_reply_submit.php](https://github.com/jakejarvis/jbb/blob/87b606797414b2fe563af85e269566fc5e076cc5/delete_reply_submit.php#L9))
```php
<?php
$query2 = "DELETE FROM jbb_replies
WHERE replyID ='$replyID'";
$result2 = mysql_query ($query2)
or die ($query2);
?>
```
Sessions based on storing an auto-incremented user ID in a cookie. ([login_submit.php](https://github.com/jakejarvis/jbb/blob/87b606797414b2fe563af85e269566fc5e076cc5/login_submit.php#L28))
```php
<?php
session_id($user->userID);
session_start();
$_SESSION["ck_userID"] = $user->userID;
$_SESSION["ck_username"] = $user->username;
$_SESSION["ck_groupID"] = $user->groupID;
?>
```
Viewing a "private" message based solely on a sequential message ID. ([pm_view.php](https://github.com/jakejarvis/jbb/blob/87b606797414b2fe563af85e269566fc5e076cc5/pm_view.php#L13))
```php
<?php
$query1 = "SELECT * FROM jbb_pm WHERE pmID = '$pmID'";
?>
```
Incredibly ambitious emoticon and [BBCode](https://en.wikipedia.org/wiki/BBCode) support. I honestly can't begin to explain this logic. ([functions.php](https://github.com/jakejarvis/jbb/blob/87b606797414b2fe563af85e269566fc5e076cc5/functions.php#L18))
```php
<?php
$replacement = '<IMG SRC=images/emoticons/smile.gif>';
$replacement2 = '<IMG SRC=images/emoticons/bigsmile.gif>';
$replacement3 = '<IMG SRC=images/emoticons/frown.gif>';
$replacement4 = '<IMG SRC=images/emoticons/crying.gif>';
$replacement5 = '<IMG SRC=images/emoticons/blush.gif>';
// ... yada yada yada ...
$replacement21 = '<a href="';
$replacement22 = '">';
$replacement23 = '</a>';
$replacement24 = '<FONT COLOR="';
$replacement25 = '</FONT>';
$replacement26 = '<FONT SIZE="';
$replacement27 = '<BR>';
$topicval = str_replace(':)', $replacement, $topicval);
$topicval = str_replace(':D', $replacement2, $topicval);
$topicval = str_replace(':(', $replacement3, $topicval);
$topicval = str_replace(':crying:', $replacement4, $topicval);
$topicval = str_replace(':blush:', $replacement5, $topicval);
// you get the point...
$topicval = str_replace('[URL=', $replacement21, $topicval);
$topicval = str_replace(':]', $replacement22, $topicval);
$topicval = str_replace('[/URL]', $replacement23, $topicval);
$topicval = str_replace('[FONT COLOR=', $replacement24, $topicval);
$topicval = str_replace('[/FONT]', $replacement25, $topicval);
$topicval = str_replace('[FONT SIZE=', $replacement26, $topicval);
$topicval = str_replace('
', $replacement27, $topicval);
// repeated five more times throught the code...
?>
```
Saving new passwords as plaintext — probably the least problematic problem. ([register_submit.php](https://github.com/jakejarvis/jbb/blob/87b606797414b2fe563af85e269566fc5e076cc5/register_submit.php#L10))
```php
<?php
$query = "INSERT INTO jbb_users (username, password, email, avatar) VALUES ('$username','$password','$email','images/avatars/noavatar.gif')";
?>
```
I guess I gave up on counting `$query`s by ones... ([functions.php](https://github.com/jakejarvis/jbb/blob/87b606797414b2fe563af85e269566fc5e076cc5/functions.php#L231))
```php
<?php
while ($topic = mysql_fetch_object($result30)) {
$query40 = "SELECT * FROM jbb_users WHERE userID = '$topic->userID'";
$result20 = mysql_query($query40)
or die ($query40);
$query50 = "SELECT * FROM jbb_replies WHERE replyID = '$replyID'";
$result50 = mysql_query($query50)
or die ($query50);
$reply = mysql_fetch_object($result50);
$query60 = "SELECT * FROM jbb_users WHERE userID = '$reply->userID'";
$result60 = mysql_query($query60)
or die ($query60);
$user = mysql_fetch_object($result60);
$query7 = "SELECT * FROM jbb_topics WHERE userID = '$reply->userID'";
$result7 = mysql_query($query7)
or die ($query7);
$query8 = "SELECT * FROM jbb_replies WHERE userID = '$reply->userID'";
$result8 = mysql_query($query8)
or die ($query8);
$usertopics = mysql_numrows($result7);
$userreplies = mysql_numrows($result8);
}
?>
```
The installation "wizard" (that's the joke, I presume...) ([sql_submit.php](https://github.com/jakejarvis/jbb/blob/87b606797414b2fe563af85e269566fc5e076cc5/setup/sql_submit.php))
<figure>
<img
src="/static/images/notes/my-first-code/jbb-screen1.png"
width="865"
height="458"
alt="JBB Installation Wizard"
/>
<figcaption>JBB Installation Wizard</figcaption>
</figure>
And finally, JBB's actual interface... or literally as much of it as I could get to function in 2019. ([index.php](https://github.com/jakejarvis/jbb/blob/87b606797414b2fe563af85e269566fc5e076cc5/index.php))
<figure>
<img src="/static/images/notes/my-first-code/jbb-screen3.png" width="865" height="561" alt="JBB Homepage" />
<figcaption>JBB Homepage</figcaption>
</figure>
<figure>
<img src="/static/images/notes/my-first-code/jbb-screen4.png" width="865" height="493" alt="JBB Post" />
<figcaption>JBB Post</figcaption>
</figure>

View File

@ -0,0 +1,109 @@
---
title: "Netlify Analytics Review"
date: 2019-11-13T08:21:22-0500
description: "Netlify has released Netlify Analytics, a tracking tool that's the only one of its kind, prioritizing privacy and speed."
tags:
- Review
- Analytics
- Data
- Netlify
- Privacy
- JAMStack
image: "/static/images/notes/netlify-analytics-review/overview.png"
---
I've been trying out [Netlify Analytics](https://www.netlify.com/products/analytics/) on this site for over a month now and have some quick thoughts about this unique offering in a world full of bloated and invasive tracking scripts.
<img
src="/static/images/notes/netlify-analytics-review/pageviews-2.png"
width="865"
height="361"
alt="Pageview charts on Netlify Analytics"
/>
## 👍&nbsp; Pros
Pretty much all of the benefits of Netlify Analytics stem from the fact that it's **purely server-side software**. This is what singularly sets it apart from [Google Analytics](https://analytics.google.com/analytics/web/) — by _far_ the [status quo](https://trends.builtwith.com/analytics/Google-Analytics) — and even self-hosted, open-source applications I've tried like [Matomo](https://github.com/matomo-org/matomo) and [Fathom](https://github.com/usefathom/fathom).
### ⚡&nbsp; Speed
To start using Netlify Analytics, you press a few buttons on the Netlify dashboard and voilà. No need to copy and paste some obfuscated JavaScript snippet into the `<head>` of each page, which is a painful task for those of us who care about speed and efficiency on the web.
On top of sending yet another DNS request to one of Google's domains — and more HTTP payloads for each outgoing click, file downloaded, etc. — Google's `analytics.js` script is currently 43 KB. For a site like [nytimes.com](https://www.nytimes.com/), which transfers **nearly 20 MB** on its homepage, this is negligible. But for simple sites like mine, which I've [painstakingly optimized](https://gtmetrix.com/reports/jarv.is/uOzCBKlv) (mostly for fun, don't judge), that doubles the size of my homepage. Matomo's script, weighing in at 65 KB, made it even worse.
### 🕵️‍♂️&nbsp; Privacy
This is the big one.
In the age of GDPR (the [General Data Protection Regulation](https://en.wikipedia.org/wiki/General_Data_Protection_Regulation) in Europe), when using analytics tools and trackers without popping up a [cookie consent prompt](https://www.freeprivacypolicy.com/blog/cookie-consent-examples/) on each new visit can get you fined millions of euros, Netlify Analytics stands alone. Netlify promises its product is [fully GDPR compliant](https://docs.netlify.com/monitor-sites/analytics/). CEO Matt Biilmann [explains](https://thenewstack.io/the-netlify-web-platform-adds-server-side-analytics-aimed-at-privacy/):
> "One of the things that has come out of GDPR is that a lot of large companies do intensive tracking of individual users — running scripts across a lot of different sites that capture a lot of detailed information from the browser. That puts you in the position where you have a ton of data on all kinds of people."
And even outside of Europe, scrapping the tracking scripts on your site just makes you a courteous netizen (God, I hate that word). Not only does Google Analytics provide _you_ with detailed information on your visitors; by default, you're also sharing that data with Google itself, to the point where they can pinpoint your [age, gender, and even your interests](https://support.google.com/analytics/answer/2799357?hl=en) by cross-referencing data with your Google account and your behavior on other sites using Google Analytics.
Instead, Netlify Analytics pulls and compiles data from server logs on each of their CDN edge nodes, rather than having the visitor's browser push data about itself back up to a third-party's endpoint.
Netlify does store some short-term data, like IP addresses, as any normal hosting provider does. But for the purposes of analytics, the data is anonymized and only used to determine things like unique visitors vs. individual page views — and not shown to the customer. [Netlify's DPA](https://www.netlify.com/gdpr/) (Data Processing Agreement) is one of the most conservative I've seen on the web.
### 🛑&nbsp; AdBlock Immunity
Ad blocking is becoming commonplace on the World Wide Web with [over 25% of users](https://www.statista.com/statistics/804008/ad-blocking-reach-usage-us/) reportedly installing extensions to do so as soon as their new browser touches the net. And for good reason, since most of them also [block cross-site tracking scripts](https://moz.com/blog/analytics-black-holes) like Google's by default.
That's a _huge_ chunk of visitors missing that Netlify Analytics gains back for you — and probably far more if your audience is tech-savvy like those reading this post likely are. (Some might even [block JavaScript completely](https://www.gnu.org/philosophy/javascript-trap.en.html) using extensions like [NoScript](https://addons.mozilla.org/en-US/firefox/addon/noscript/).)
<img
src="/static/images/notes/netlify-analytics-review/pages.png"
width="865"
height="390"
alt="Pageview and 404 tracking on Netlify Analytics"
/>
Another tangential benefit you simply don't get from JavaScript-based tools like Google Analytics is the "Resources Not Found" box, which separates out URLs that resulted in a 404 Not Found error. Because of the 404 tracking, I discovered how many people were still subscribed to my posts via RSS from when I used WordPress _years_ ago, and I was able to redirect `/feed` and `/rss` to the new location.
_Side note: This section has also become cluttered with requests from script kiddies who are scanning the internet for files like `login.php` and `/wp-admin` and `AspCms_Config.asp` (huh?) — but that's a whole separate problem for another day._
## 👎&nbsp; Cons
### 💰&nbsp; Price
Netlify is one of the most awesome free-as-in-beer services on the web today, providing a fast CDN and instant deployments at zero cost (up to a pretty insane amount, of course). But if you want to add Netlify Analytics, your bill suddenly jumps to [\$9 a month](https://www.netlify.com/pricing/#analytics). **Nine dollars!** That's over **\$100 per year!** If you have more than 250,000 visitors per month, the cost can be even higher (to the point where you'll need to contact Netlify's sales team).
It makes sense that Netlify needs to subsidize the cost of providing free enterprise-grade web hosting for the rest of its non-enterprise users to stay alive. But when Google Analytics is free, this is a pretty tough ask for any hobbyist — even if Google is [getting more from them](https://support.google.com/analytics/answer/1011397?hl=en) than they are from Google. 😬
### 📈&nbsp; Accuracy
<img
src="/static/images/notes/netlify-analytics-review/sources-bandwidth.png"
width="865"
height="422"
alt="Referrer and bandwidth tracking on Netlify Analytics"
/>
Clearly, as much as I wish they did, 60,000+ visitors didn't type my website directly into the URL bar in the past month. Some of my articles have been circulating on Hacker News, Reddit, Twitter, etc. — none of which have even made a blip on the dashboard.
There are various possible reasons that referrers aren't being sent, mostly relating to HTTP headers and [increasingly sensible](https://blog.mozilla.org/blog/2019/06/04/firefox-now-available-with-enhanced-tracking-protection-by-default/) browser defaults, that aren't Netlify's fault. But this section is the most obvious example of important data you can miss out on by not tracking incoming visitors via JavaScript.
Another benefit of using Google's own analytics service becomes glaringly apparent here: I have **no idea** which search terms were used to reach which page. Netlify could mitigate this a bit by separating out referrers for each individual page, though, so at least I'd know which pages were having the most organic success on search engines.
One more note: since Netlify doesn't process IP addresses or user agents, bots crawling your site (like [Googlebot](https://support.google.com/webmasters/answer/182072?hl=en) and [Bingbot](https://www.bing.com/webmaster/help/which-crawlers-does-bing-use-8c184ec0)) get counted towards your stats, possibly overinflating your ego a little more than it should.
### ⏱️&nbsp; Historical Data
<img
src="/static/images/notes/netlify-analytics-review/overview.png"
width="865"
height="355"
alt="Overview of Netlify Analytics stats"
/>
Trying out Netlify Analytics meant switching this site from [GitHub Pages](https://pages.github.com/) to Netlify — something I still have mixed feelings about. But if I had been on Netlify the entire time, I would have gotten thirty days of historical stats backfilled right off the bat, from before I even started paying for Analytics.
Sure, this is a cool bonus. However, "thirty days" has another meaning on Netlify Analytics: it's the **absolute maximum amount of data** you can access. Period, full stop. On your Analytics dashboard, you can see a window of the past month on your site — and that's all. Day 31 is gone, seemingly forever.
I hope Netlify proves me wrong in Version 2, since analyzing trends over the course of a year (or two, or five) is an **integral reason** to track visitor behavior in the first place. Otherwise, it's nearly impossible to tell which piece of content or which new feature caused your website to explode in popularity, unless you're meticulously watching it happen in real time.
---
I'm _super_ happy to see an investment in privacy-minded solutions for analytics, and [the Netlify team should be proud](https://www.youtube.com/watch?v=jMo0oQwTVak) of what they've built. And for the time being, I'm willing to continue forking over the nine bucks per month to give Netlify a chance to keep building upon this awesome (and, dare I say, [courageous](https://www.theverge.com/2016/9/7/12838024/apple-iphone-7-plus-headphone-jack-removal-courage)) concept. But only time will tell if others are willing to do the same — and if they are, how long they're willing to wait before resorting back to injecting bloated JavaScript snippets and hoarding invasive amounts of our data to share with the [behemoths of the internet](https://www.google.com/).
Hopefully it happens within a window of 30 days, though, or else Netlify will be none the wiser! 😉

View File

@ -0,0 +1,107 @@
---
title: '"No Homo!" — Still Rap''s Motto in 2012?'
date: 2013-11-22 11:58:20-0400
description: 'This essay was written for Professor David Valdes-Greenwood''s "Love & Sexuality" class at Tufts University in April 2012.'
tags:
- Essay
- Homosexuality
- Music
- Rap
- Tufts University
image: "/static/images/notes/no-homo-still-raps-motto/1_b41ztscbaxqi60snwsswfw.jpg"
---
<figure>
<img src="/static/images/notes/no-homo-still-raps-motto/1_b41ztscbaxqi60snwsswfw.jpg" width="865" height="364" />
<figcaption>
This essay was written for Professor David Valdes-Greenwood's "Love & Sexuality" class at{" "}
<a href="https://www.tufts.edu/" target="_blank" rel="noopener noreferrer">
Tufts University
</a>{" "}
in April 2012.
</figcaption>
</figure>
> _Too many faggot n\*ggas clocking my spending, exercising your gay-like minds like Richard Simmons ... Fucking faggot-ass light skin n\*ggas, get the fuck out of my face ... It's crazy how you can go from being Joe Blow, to everybody on your dick, no homo ... You homo n\*ggas getting AIDS in the ass, while the homie here's trying to get paid in advance ... If y'all leave me alone this wouldn't be my M.O., I wouldn't have to go, eenee-meene-minie-moe,' catch a homo by his toe, man I don't know no more..._
What do all of these lyrics have in common? Two things. Firstly, they are all blatant in their use of anti-gay slurs and graphically homophobic language. And secondly, they've each been written and recorded by one of the top five mainstream rap artists of 2011: Jay-Z, Diddy, Kanye West, Lil Wayne, and Eminem — a worshipped all-star team in music with a combined income of $82 million last year alone, with multi-platinum records endorsed by and distributed through Universal, Sony, and Warner Brothers, and with endorsement deals from Gatorade, HP, Pepsi, Chrysler, Lipton, and others.
Of course, these five rappers are protected by their right to free speech to speak these irrefutably homophobic lyrics into a studio microphone, release them onto future multi-platinum CDs, and get played by world-renowned New York City radio stations. But what about their gay and bisexual counterparts? A fame-aspiring gay rapper has just as much of a right, if not more, to record music as Jay-Z and Eminem record, and as much of a right to speak publicly as Ellen DeGeneres and Rosie O'Donnell speak. So, to put it candidly, where are all the gay rappers? I'll give you a minute to scroll through your iPod.
Is the increasingly apparent void of gay (or even bi) male rappers due to a lack of demand or a lack of supply? Or, do gay rappers get automatically turned away at the doors of Universal, Sony, and Warner Brothers, over fears of losing profit? Let's follow a hypothetical gay rapper through the intricacies and politics of the music industry to answer one simple, overarching economical question: How successful would a young, talented, and coincidentally gay male rapper be in 2012?
To get a sense of the industry a new gay rapper would be walking into, I surveyed 62 college-aged rap fans at Tufts University. Before introducing the prospect of a gay rapper to them, I wanted to gauge their feelings about the homophobia in pre-existing mainstream rap music. The results were staggering: 92% of the respondents said that hearing "faggot" or "no homo" doesn't stand out to them while listening to a song, and 100% wouldn't stop listening to that song or that artist after hearing these phrases. On the flip side, none of the 62 respondents — including one gay sophomore — could name a gay rapper. The existing landscape of the rap industry became rapidly clear: there are no gays on the radar, except when "homo" or "fag" rhymes with the line before it.
My next inquiry was about whether there's room for a gay person in the mainstream rap industry. Is the clear absence of gay voices from mainstream rap by the choice of gay rappers, or is there no demand from music listeners? 90% of the college respondents claimed that they would listen to a gay rapper (under the condition that he or she is talented, of course). However, only 4% could reasonably predict that a talented gay rapper would be commercially successful. When asked to explain, the responses included that "the ridicule and internal conflict [would not be] worth the possible profit for record labels," that "people would be embarrassed to have their iPod seen with the rapper's name playing," and that "rap is already about women, women, and women, and it's been around for too long to change that."
It became apparent to me that there is still an ethical divide between the rap industry and the rest of America. In 2012, there are few areas where undisguised and unapologetic homophobia is not only accepted, but rewarded with money and power. (Rap and the Republican presidential nomination race come to mind.) Every few years, we see the issue of rap and homophobia as front-page news, but the time between these climaxes of public outrage is filled with self-encouraging homophobic songs that get no backlash at all.
<figure>
<img src="/static/images/notes/no-homo-still-raps-motto/66574-132xjztnwqcm40hmdrec08q.jpg" width="700" height="464" />
<figcaption>Frank Micelotta/Getty Images</figcaption>
</figure>
Eminem is a prime example of this. After rapping about "homos" and "fags" for years, his third studio album, _The Marshall Mathers LP_, finally saw mainstream recognition and acclaim, including the nomination for Best Rap Album and Album of the Year at the 2001 Grammy Awards. After both the National Academy of Recording Arts & Sciences and CBS "endured a storm of protest over the rapper's best album nomination" due to his use of homophobic slurs, Eminem announced a duet with Elton John to be performed at the Grammy ceremony. "I'd rather tear down walls between people than build them up. If I thought for one minute that he was hateful, I wouldn't do it," John said in defense of the performance.
However, the newly announced alliance was still met with criticism from the Gay & Lesbian Alliance Against Defamation, or GLAAD. Media director Scott Seomin called the move "hurtful" and "embarrassing," and voiced public regret for giving John the foundation's yearly award the year before, claiming, "Elton's actions now totally violate the spirit of that award."
More recently, in late 2011, MTV's Video Music Awards also came under fire from GLAAD for recognizing the sophomore album from 20-year-old rapper Tyler, The Creator. According to _NME Magazine_, the album from Tyler, The Creator and his group, Odd Future, "uses the word faggot' and its variants a total of 213 times." In defense of his lyrics, Tyler told NME:
> I have gay fans and they don't really take it offensive, so I don't know. If it offends you, it offends you. I'm not homophobic. I just think faggot' hits and hurts people. It hits. And gay' just means you're stupid. I don't know, we don't think about it, we're just kids. We don't think about that shit. But I don't hate gay people. I don't want anyone to think I'm homophobic.
The seemingly clear disconnect between rap and the rest of America becomes somewhat blurred when you factor in that the award Tyler, The Creator won was determined by a popular vote of MTV's fairly young audience. Sara Quin, 20-year-old Canadian indie singer and half of the rock duo Tegan and Sara, expressed her frustration with both Tyler and the music industry on her blog. "While an artist who can barely get a sentence fragment out without using homophobic slurs is celebrated on the cover of every magazine, blog and newspaper," she wrote, "I'm disheartened that any self-respecting human being could stand in support with a message so vile." Tyler simply responded with, "If Tegan and Sara need some hard dick, hit me up!"
With both homophobia and "womanizing" being so prevalent in the mainstream rap industry, one has to wonder if these themes are not only accepted, but also necessary to become a successful rapper. When the top five rappers of 2011 openly use homophobic slurs in _Billboard_ Top 100 songs, is homophobia in rap simply a vicious cycle of new rappers trying to climb the ladder to work with these acclaimed rappers by using similar lyrics and style? Are rappers simply afraid to "come out" as non-homophobic in fears that this will sever ties to more successful rappers which are necessary in an industry full of connections and word-of-mouth?
According to mainstream rapper and insider Fat Joe, this fear is very much real. But as of 2011, he says, there's no reason for a rapper to hide his sexuality. In an interview with _Vibe Magazine_, Joe speculated, "I'm pretty sure I've done songs with gay rappers...In 2011 you gotta hide that you gay? Like, be real. Yo, I'm gay, what the fuck!' Fuck it if people don't like it."
Based on his inside experience, Joe continued to claim that a gay rapper would have an outpouring of support from inside even the mainstream rap industry, even going as far as calling the entertainment industry a "gay mafia," including everyone from "editorial presidents of magazines, PDs at radio stations, and the people that give you awards at award shows. This is a fucking gay mafia, my man; they are in power."
Similarly, a few months before Fat Joe came out publicly favoring gay rappers, Grammy-nominated rapper The Game spoke out less strongly but still in support of the idea. In an interview with DJ Vlad, Game told gay rappers:
> I think there are several rappers that are in the closet and gay, and see those are the type of gay people — the only type of gay people that I have a problem with. I don't have a problem with gay people. Game don't have a problem with gay people. It ain't cool to be in the closet. If you gay, just say you gay. Be gay and be proud.
A year earlier, in 2009, Queens rapper N.O.R.E. also revealed to DJ Vlad:
> I have recorded, not with people who are openly gay, but people who are closet gays. I've got songs, you know, Google it. I'm positive I have worked with a gay rapper. There is one and he won't get me to say the name. Once he's a success story to the point where he can't be stopped, then yeah, he's gonna come out the closet... It's not a big secret, everybody is gonna be like, "Oh yeah, I knew that."
Several other rappers have recently been vocal against homophobia. Nicki Minaj, protégé of Lil Wayne, said in an interview last year with _Out Magazine_, "Normally, Wayne probably wouldn't have gay guys coming to see his shows much, but they're definitely a big part of my movement, and I hope they'd still come out and see me. I think that will be really, really interesting, just to start bridging that gap." Up-and-coming 23-year-old rapper A$AP Rocky, admitted last year to Pitchfork.com, "I used to be homophobic, but that's fucked up. I had to look in the mirror and say, All the designers I'm wearing are gay.'"
<figure>
<img src="/static/images/notes/no-homo-still-raps-motto/f9d7a-1gad6zdgng2-mjsedg5igwa.jpg" width="350" height="527" />
<figcaption>Sarah Taylor/Fashion Magazine</figcaption>
</figure>
Unfortunately, not all rappers — including and especially the most popular and celebrated — are not as enlightened as today's up-and-comers such as Nicki Minaj and A$AP Rocky. Kanye West, one of the rappers quoted before for shouting "no homo" on Jay-Z's number-one single _Run This Town_ and (in)famous for speaking what's on his mind, was the target of countless questions about his sexuality after his sudden attendance at Paris fashion shows and interest in women's designer clothing. When asked by DJ Sway for MTV News to respond to accusations from fans that he "dresses gay," West responded, "Your dress don't give away whether or not you like a man. Think about actors that straight dress up like a woman or something like that. People wanna label me and throw that on me all the time, but I'm so secure with my manhood."
West, disagreeing with Fat Joe's claim of being surrounded by gay members of the music industry, told Sway that, before releasing a music video for a 2008 collaboration with rapper Fonzworth Bentley, "There was people calling me before we dropped it, like Man y'all shouldn't put that out with y'all dancing, man. People gonna say y'all gay!'" West also disagreed with the prospect of a gay rapper, making a claim that the industry has actually gotten more homophobic in recent years. "Back in the day, people used to have songs like Get In That Ass' or something like that," West said. "Someone would never make a song like that today because they'd be like Whoa! I can't make no song like that! People gonna call me gay!'"
While the sentiment from mainstream rappers is becoming increasingly supportive of all sexualities, West's automatic instinct to defend himself so passionately against rumors about his own sexuality reflects no such sentiment from the community of rap fans and critics. In other words, maybe the record executives are justified to think that a gay rapper would jeopardize the one thing they are hired to protect: a profitable return on investments in recording contracts, marketing, and concert venues.
<figure>
<img src="/static/images/notes/no-homo-still-raps-motto/a5c2a-1fkblnzkye3g04gdvsbbtpa.jpg" width="580" height="389" />
<figcaption>Amy Odell/New York Magazine Fashion</figcaption>
</figure>
Lil Wayne's performance at MTV's Video Music Awards last year showed the community's lack of progress in the area of homophobia. The performance generated tons of instantaneous buzz on the Internet, but not for the reasons Wayne had hoped. Instead of his musical performance being discussed, the topic instead turned to his wardrobe. Viewers of the live award show started wondering and asking online, _"Is Lil Wayne wearing women's pants right now?"_
Sure enough, _Rolling Stone_ confirmed with the fashion store Tripp NYC that Wayne was sporting their ladies' leopard-print jeggings that retail online for $44. _Out Magazine_'s assistant editor Max Berlinger spoke in support of Wayne, attributing his choice of clothes to Dandyism, or "extreme visual paradigms that are manifested in a completely overt way and also heavily rooted in consumerism." Berlinger, when asked to elaborate on artists like Kanye wearing women's blouses and calling it individualism, simply responded with, "Fuck all that theoretical bullshit. At the end of the day, I just want someone to look confidently like themselves, which Lil Wayne did perfectly". However, Wayne's fans vocally disagreed. A Twitter account, @Waynes_Jeggings, was created almost immediately after the performance, and spent the rest of the night questioning Wayne's sexuality (the messages have since been deleted).
<figure>
<img src="/static/images/notes/no-homo-still-raps-motto/a805a-1ghqzd91ei4fdntwmzwxw6g.jpg" width="350" height="511" />
<figcaption>Martin Rose/Getty Images</figcaption>
</figure>
In the most revealing and straightforward social experiment yet, 21-year-old rapper Lil B, famous for his intentionally offbeat rhythm, extremely loose rhymes, and, according to him, over 3,000 songs, some with ridiculous titles such as "I'm Miley Cyrus," "I'm God," "I'm Orange Juice," and "Wonton Soup," decided to test the rap community's homophobia once and for all. In April of last year, Lil B announced during his Coachella performance that his next independently released album would be titled _I'm Gay_. Lil B elaborated on the title, claiming "that he does not partake in that lifestyle but, but he wants to make a statement about the power of words, or lack thereof," but little of his reasoning made it past the headlines and onto the radar of rap fans other than the title, _I'm Gay_.
As he predicted (and hoped for — any publicity is good publicity, right?), the entire entertainment industry was in uproar over his announcement for all different reasons. Rap fans hoped that the title was just a gimmick, while GLAAD released statements on the other side of the spectrum, saying, "Lil B knows that words matter. Slurs have the power to fuel intolerance. We hope that Lil B's album title is not just a gimmick, and is really a sincere attempt to be an ally. He has the platform and the voice. We hope he uses it in a positive way." Even several rappers spoke out about Lil B's title choice, including a notably politically active rapper, Talib Kweli. "I'm like, now that's a fuckin' social experiment if I've ever heard one," Kweli told _XXL Magazine_. He continued:
> I don't care who you sleep with at the end of the day. I don't care if Lil B's gay or not. It doesn't change my life in any way, but for him to name his album _I'm Gay_ issues such a challenge to his fans. I'm not sure if it's brilliant or not, but what he did with that, in one fell swoop, was challenge every single bandwagon fan. Like are you really down with me or not. And me as an artist, I have no choice but to respect that.
Kweli, when asked to comment more specifically on the sexuality aspect of both the title and the reaction, said, "I'm happy to see young hip-hop heads move away from homophobia. Regardless of what your stance is on gay people, homophobia or the act and practice of it, is extra wack."
When questioned on his motivations behind the title by _Vulture Magazine_ and asked to respond to GLAAD's plea for an ally, not a mockery, Lil B affirmatively responded, "I am an ally. I am a man that loves women, but I am an ally." He acknowledged that sexuality is still a very taboo topic in rap music, and that "there are some bridges and gaps that we as a people need to close. It takes a person to be brave enough to do that and wake people up. I wanted to be that first artist to be brave enough to do it for the people. In 100 years, people will look back and appreciate it."
Maybe in 100 years from now, _I'm Gay_ would have been a chart-topping success. But in 2011, the album peaked at #56 on the Billboard R&B/Hip-Hop charts and failed to make it onto the Hot 100 Albums chart at any point after its release. After selling only 1,700 copies in its first week, Lil B released the album for free on his social networking accounts.
Based on the insider reports and public fan reactions, it seems as though in 2012, the big-time industry influencers are talking the talk. Now, the onus to walk the walk is on every rap fan — and record producer — across the country. It's up to you to prove Lil B right: hopefully, in 100 years, you'll wonder why this article was even written. But for now, it looks like too many words rhyme with "no homo" for this to be the case.

View File

@ -0,0 +1,244 @@
---
title: "Ranking 2020 Presidential Candidates's 404 Pages"
date: 2019-10-30 13:58:39-0400
description: "Each of the 2020 presidential candidates's 404 Not Found pages, ranked."
tags:
- Politics
- Campaign 2020
- Rankings
- Attempted Humor
image: "/static/images/notes/presidential-candidates-404-pages/obama-laughing.jpg"
---
<figure>
<img
src="/static/images/notes/presidential-candidates-404-pages/obama-laughing.jpg"
width="865"
height="460"
alt="President Barack H. Obama, probably ranking 404 pages."
/>
<figcaption>President Barack H. Obama, probably ranking 404 pages.</figcaption>
</figure>
Ever since [President Obama injected technology](https://arstechnica.com/information-technology/2012/11/built-to-win-deep-inside-obamas-campaign-tech/) into presidential politics in a historic way, one of the few bright spots of the incredibly long and exhausting race for me has been inspecting each candidate's campaign website. They end up revealing a great deal about how much each of them is willing to invest in the internet, and how young and innovative (and potentially funny) the staff members they attract are.
More recently, though, little-known hidden Easter eggs on ["404 Not Found"](https://en.wikipedia.org/wiki/HTTP_404) pages have become an outlet for the candidates' overworked web designers to let out some humor in a sea of otherwise serious policy pages. Below are the 404 pages on each of the current candidate's websites, along with my ranking of them — setting politics aside, for once.
## 1. Elizabeth Warren — [elizabethwarren.com](https://elizabethwarren.com/asdfasdf404)
I'm a _huge_ sucker for Kate McKinnon's spot-on impression of Warren on Saturday Night Live. And [unfortunately](https://twitter.com/realdonaldtrump/status/1097116612279316480), seeing a campaign embrace SNL is like a breath of fresh air these days. [Watch all of the Kate McWarren videos so far here; you won't regret it.](https://www.nbc.com/saturday-night-live/cast/kate-mckinnon-15056/impersonation/elizabeth-warren-287903)
<img
src="/static/images/notes/presidential-candidates-404-pages/warren.png"
width="865"
height="579"
alt="Elizabeth Warren"
/>
## 2. Bernie Sanders — [berniesanders.com](https://berniesanders.com/asdfasdf404/)
Although the designer who selected this GIF likely had _thousands_ of choices when searching "[Bernie finger wagging GIF](https://www.google.com/search?q=Bernie+finger+wagging+GIF&tbm=isch&tbs=itp:animated)," the text beside it is well-written and funny — even though we both know putting a page at [berniesanders.com/zxcliaosid](https://berniesanders.com/zxcliaosid/) probably won't be a top priority of a President Sanders.
<video
url={[
{ src: "/static/images/notes/presidential-candidates-404-pages/sanders.webm", type: "video/webm" },
{ src: "/static/images/notes/presidential-candidates-404-pages/sanders.mp4", type: "video/mp4" },
]}
config={{
file: {
attributes: {
autoPlay: true,
loop: true,
volume: 0,
muted: true,
},
},
}}
controls={false}
/>
## 3. Joe Biden — [joebiden.com](https://joebiden.com/asdfasdf404)
Uncle Joe has a nice and simple 404 page. I like it, along with the Ray-Bans and his choice of vanilla ice cream.
<img src="/static/images/notes/presidential-candidates-404-pages/biden.png" width="865" height="539" alt="Joe Biden" />
## 4. Beto O'Rourke — [betoorourke.com](https://betoorourke.com/asdfasdf404)
A ballsy move, considering Beto's infamous [DUI arrest](https://www.politifact.com/texas/statements/2019/mar/14/club-growth/beto-orourke-arrested-dwi-flee-scene/) in the '90s — but still a clever ask for a donation and a great use of a GIF, even if it's left over from his Senate campaign.
<video
url={[
{ src: "/static/images/notes/presidential-candidates-404-pages/orourke.webm", type: "video/webm" },
{ src: "/static/images/notes/presidential-candidates-404-pages/orourke.mp4", type: "video/mp4" },
]}
config={{
file: {
attributes: {
autoPlay: true,
loop: true,
volume: 0,
muted: true,
},
},
}}
controls={false}
/>
## 5. Kamala Harris — [kamalaharris.org](https://kamalaharris.org/asdfasdf404)
Another clean and simple page with a top-notch GIF. It injected some emotion into visiting [kamalaharris.com/alskdjf](https://kamalaharris.com/alskdjf).
<video
url={[
{ src: "/static/images/notes/presidential-candidates-404-pages/harris.webm", type: "video/webm" },
{ src: "/static/images/notes/presidential-candidates-404-pages/harris.mp4", type: "video/mp4" },
]}
config={{
file: {
attributes: {
autoPlay: true,
loop: true,
volume: 0,
muted: true,
},
},
}}
controls={false}
/>
## 6. Pete Buttigeg — [peteforamerica.com](https://peteforamerica.com/asdfasdf404/)
I love, love, _love_ Pete's design for his whole campaign, and his beautiful 404 page is no exception. In case you didn't know, Pete for America has an entire ["Design Toolkit"](https://design.peteforamerica.com/) publicly available for all to view and use, with really cool and in-depth explanations for all of their choices — even their [color palette](https://design.peteforamerica.com/colors). Very progressive indeed.
<img
src="/static/images/notes/presidential-candidates-404-pages/buttigeg.png"
width="865"
height="344"
alt="Pete Buttigeg"
/>
## 7. Cory Booker — [corybooker.com](https://corybooker.com/asdfasdf404/)
Love the photo choice. But although pains me to go against my Senator from my home state, I still _cannot stand_ his choice of font. Oh well, I guess that's now a criterion for running for president in 2020.
<img
src="/static/images/notes/presidential-candidates-404-pages/booker.png"
width="865"
height="503"
alt="Cory Booker"
/>
## 8. Andrew Yang — [yang2020.com](https://www.yang2020.com/asdfasdf404)
Not sure if donating to Yang 2020 will help put a page at [yang2020.com/alsdjfzoif](https://www.yang2020.com/alsdjfzoif) — the actual URL I visited to grab this screenshot — but the Bitmoji Andrew looks pretty chill.
<img src="/static/images/notes/presidential-candidates-404-pages/yang.png" width="865" height="470" alt="Andrew Yang" />
## 9. Amy Klobuchar — [amyklobuchar.com](https://amyklobuchar.com/asdfasdf404)
This is the 404 page of someone who won't forget the [Midwestern roots](https://en.wikipedia.org/wiki/Uff_da) she comes from once she moves into the White House...or writes a memoir about her campaign from her Minnesota home.
<img
src="/static/images/notes/presidential-candidates-404-pages/klobuchar.png"
width="865"
height="456"
alt="Amy Klobuchar"
/>
## 10. Steve Bullock — [stevebullock.com](https://stevebullock.com/asdfasdf404)
I'll never publicly say anything against a good Dad joke. This is no exception.
<img
src="/static/images/notes/presidential-candidates-404-pages/bullock.png"
width="865"
height="467"
alt="Steve Bullock"
/>
## 11. Michael Bennet — [michaelbennet.com](https://michaelbennet.com/asdfasdf404)
Another quality Dad joke here.
<img
src="/static/images/notes/presidential-candidates-404-pages/bennet.png"
width="865"
height="543"
alt="Michael Bennet"
/>
## 12. John Delaney — [johndelaney.com](https://www.johndelaney.com/asdfasdf404)
Yet another Dad joke? I honestly had the hardest time ranking these three.
<img
src="/static/images/notes/presidential-candidates-404-pages/delaney.png"
width="865"
height="405"
alt="John Delaney"
/>
## 13. Marianne Williamson — [marianne2020.com](https://www.marianne2020.com/asdfasdf404)
A 404 page only a motivational author and speaker running for president could envision.
<img
src="/static/images/notes/presidential-candidates-404-pages/williamson.png"
width="865"
height="357"
alt="Marianne Williamson"
/>
## 14. The Donald — [donaldjtrump.com](https://donaldjtrump.com/asdfasdf404)
I guess this would be slightly humorous...four years ago. Time to move on from your middle-school crush, Donny.
<img
src="/static/images/notes/presidential-candidates-404-pages/trump.png"
width="865"
height="524"
alt="Trump/Pence"
/>
---
## Disqualified Candidates...
These candidates haven't configured a custom 404 page, settling for the default Drupal or WordPress text. Do they _really_ think they can run the free world with their websites in this shape? 🙄 _&lt;/s&gt;_
### 15. Julián Castro — [julianforthefuture.com](https://www.julianforthefuture.com/asdfasdf404)
<img
src="/static/images/notes/presidential-candidates-404-pages/castro.png"
width="865"
height="316"
alt="Julián Castro"
/>
### 16. Wayne Messam — [wayneforusa.com](https://wayneforusa.com/asdfasdf404)
<img
src="/static/images/notes/presidential-candidates-404-pages/messam.png"
width="865"
height="529"
alt="Wayne Messam"
/>
### 17. Tulsi Gabbard — [tulsi2020.com](https://www.tulsi2020.com/asdfasdf404)
<img
src="/static/images/notes/presidential-candidates-404-pages/gabbard.png"
width="865"
height="333"
alt="Tulsi Gabbard"
/>
### 18. Joe Sestak — [joesestak.com](https://www.joesestak.com/asdfasdf404)
<img
src="/static/images/notes/presidential-candidates-404-pages/sestak.png"
width="865"
height="366"
alt="Joe Sestak"
/>

View File

@ -0,0 +1,88 @@
---
title: "Adding Security Headers Using Cloudflare Workers"
date: 2019-02-28 03:18:10-0400
description: "How to add important security headers to your website using Cloudflare Workers before delivering the response to the user."
tags:
- Security
- HTTP Headers
- Cloudflare
- Hosting
- Tutorial
image: "/static/images/notes/security-headers-cloudflare-workers/security-headers.png"
---
<figure>
<img
src="/static/images/notes/security-headers-cloudflare-workers/security-headers.png"
width="700"
height="275"
alt="An A+ security grade for this website!"
/>
<figcaption>
An{" "}
<a href="https://securityheaders.com/?q=jarv.is&amp;followRedirects=on" target="_blank" rel="noopener noreferrer">
A+ security grade
</a>{" "}
for this website!
</figcaption>
</figure>
In 2019, it's becoming more and more important to harden websites via HTTP response headers, which all modern browsers parse and enforce. Multiple standards have been introduced over the past few years to protect users from various attack vectors, including `Content-Security-Policy` for injection protection, `Strict-Transport-Security` for HTTPS enforcement, `X-XSS-Protection` for cross-site scripting prevention, `X-Content-Type-Options` to enforce correct MIME types, `Referrer-Policy` to limit information sent with external links, [and many, many more](https://www.netsparker.com/whitepaper-http-security-headers/).
[Cloudflare Workers](https://www.cloudflare.com/products/cloudflare-workers/) are a great feature of [Cloudflare](https://www.cloudflare.com/) that allows you to modify responses on-the-fly between your origin server and the user, similar to [AWS Lambda](https://aws.amazon.com/lambda/) (but much simpler). We'll use a Worker to add the headers.
<img
className="center"
src="/static/images/notes/security-headers-cloudflare-workers/cf-workers.png"
width="650"
height="325"
alt="Cloudflare Workers"
/>
Workers can be enabled for $5/month via the [Cloudflare Dashboard](https://dash.cloudflare.com/). (It's worth noting, once enabled, Workers can be used on _any zone_ on your account, not just one website!).
If you run your own server, these can be added by way of your Apache or nginx configuration. But if you're using a shiny static site host like [GitHub Pages](https://pages.github.com/), [Amazon S3](https://aws.amazon.com/s3/), [Surge](https://surge.sh/), etc. it may be difficult or impossible to do so.
The following script can be added as a Worker and customized to your needs. Some can be extremely picky with syntax, so be sure to [read the documentation](https://www.netsparker.com/whitepaper-http-security-headers/) carefully. You can fiddle with it in [the playground](https://cloudflareworkers.com/), too. Simply modify the current headers to your needs, or add new ones to the `newHeaders` or `removeHeaders` arrays.
```js
let addHeaders = {
"Content-Security-Policy": "default-src 'self'; upgrade-insecure-requests",
"Strict-Transport-Security": "max-age=1000",
"X-XSS-Protection": "1; mode=block",
"X-Frame-Options": "SAMEORIGIN",
"X-Content-Type-Options": "nosniff",
"Referrer-Policy": "same-origin",
};
let removeHeaders = ["Server", "Public-Key-Pins", "X-Powered-By", "X-AspNet-Version"];
addEventListener("fetch", (event) => {
event.respondWith(fetchAndApply(event.request));
});
async function fetchAndApply(request) {
// Fetch the original page from the origin
let response = await fetch(request);
// Make response headers mutable
response = new Response(response.body, response);
// Set each header in addHeaders
Object.keys(addHeaders).map(function (name, index) {
response.headers.set(name, addHeaders[name]);
});
// Delete each header in removeHeaders
removeHeaders.forEach(function (name) {
response.headers.delete(name);
});
// Return the new mutated page
return response;
}
```
Once you're done, you can analyze your website's headers and get a letter grade with [Scott Helme](https://scotthelme.co.uk/)'s awesome [Security Headers](https://securityheaders.com/) tool. His free [Report-URI](https://report-uri.com/) service is another great companion tool to monitor these headers and report infractions your users run into in the wild.
You can view my website's [full Worker script here](https://github.com/jakejarvis/jarv.is/blob/ededcc05c4a5b2650d5a7eb6f8d00496b61221e3/worker.js) and check out [the resulting A+ grade](https://securityheaders.com/?q=https%3A%2F%2Fjarv.is%2F)!

View File

@ -0,0 +1,800 @@
---
title: "Fascinating & Frightening Shodan Search Queries (AKA: The Internet of Sh*t)"
date: 2019-09-19 09:56:10-0400
description: "I've collected some interesting and scary search queries for Shodan, the internet-of-things search engine. Some return fun results, while others return serious vulnerabilities."
tags:
- Infosec
- Pentesting
- Shodan
- Internet of Things
- Dorking
image: "/static/images/notes/shodan-search-queries/shodan.png"
---
Over time, I've collected an assortment of interesting, funny, and depressing search queries to plug into [Shodan](https://www.shodan.io/), the ([literal](https://www.vice.com/en_uk/article/9bvxmd/shodan-exposes-the-dark-side-of-the-net)) internet search engine. Some return facepalm-inducing results, while others return serious and/or ancient vulnerabilities in the wild.
<figure>
<a class="no-underline" href="https://account.shodan.io/register" target="_blank" rel="noopener noreferrer">
<img
src="/static/images/notes/shodan-search-queries/shodan.png"
width="865"
height="248"
alt="Most search filters require a Shodan account."
/>
</a>
<figcaption>
<a href="https://account.shodan.io/register" target="_blank" rel="noopener noreferrer">
<strong>Most search filters require a Shodan account.</strong>
</a>
</figcaption>
</figure>
You can assume these queries only return unsecured/open instances when possible. For your own legal benefit, do not attempt to login (even with default passwords) if they aren't! Narrow down results by adding filters like `country:US` or `org:"Harvard University"` or `hostname:"nasa.gov"` to the end.
The world and its devices are quickly becoming more connected through the shiny new [Internet of ~~Things~~ Sh\*t](https://motherboard.vice.com/en_us/topic/internet-of-shit) — and exponentially [more dangerous](https://blog.malwarebytes.com/101/2017/12/internet-things-iot-security-never/) as a result. To that end, I hope this list spreads awareness (and, quite frankly, pant-wetting fear) rather than harm.
**And as always, [discover and disclose responsibly](https://www.bugcrowd.com/resource/what-is-responsible-disclosure/)! 😊**
---
### Table of Contents:
- [Industrial Control Systems](#industrial-control-systems)
- [Remote Desktop](#remote-desktop)
- [Network Infrastructure](#network-infrastructure)
- [Network Attached Storage (NAS)](#network-attached-storage-nas)
- [Webcams](#webcams)
- [Printers & Copiers](#printers-copiers)
- [Home Devices](#home-devices)
- [Random Stuff](#random-stuff)
---
## Industrial Control Systems
### Samsung Electronic Billboards [🔎 →](https://www.shodan.io/search?query=%22Server%3A+Prismview+Player%22)
```plaintext
"Server: Prismview Player"
```
<img
className="center"
src="/static/images/notes/shodan-search-queries/billboard3.png"
width="450"
height="329"
alt="Example: Electronic Billboards"
/>
### Gas Station Pump Controllers [🔎 →](https://www.shodan.io/search?query=%22in-tank+inventory%22+port%3A10001)
```plaintext
"in-tank inventory" port:10001
```
<img
className="center"
src="/static/images/notes/shodan-search-queries/7-11.png"
width="600"
height="226"
alt="Example: Gas Station Pump Inventories"
/>
### Automatic License Plate Readers [🔎 →](https://www.shodan.io/search?query=P372+%22ANPR+enabled%22)
```plaintext
P372 "ANPR enabled"
```
<img
className="center"
src="/static/images/notes/shodan-search-queries/plate-reader.png"
width="680"
height="284"
alt="Example: Automatic License Plate Reader"
/>
### Traffic Light Controllers / Red Light Cameras [🔎 →](https://www.shodan.io/search?query=mikrotik+streetlight)
```plaintext
mikrotik streetlight
```
### Voting Machines in the United States [🔎 →](https://www.shodan.io/search?query=%22voter+system+serial%22+country%3AUS)
```plaintext
"voter system serial" country:US
```
### Telcos Running [Cisco Lawful Intercept](https://www.cisco.com/c/en/us/td/docs/switches/lan/catalyst6500/ios/12-2SX/lawful/intercept/book/65LIch1.html) Wiretaps [🔎 →](https://www.shodan.io/search?query=%22Cisco+IOS%22+%22ADVIPSERVICESK9_LI-M%22)
```plaintext
"Cisco IOS" "ADVIPSERVICESK9_LI-M"
```
Wiretapping mechanism outlined by Cisco in [RFC 3924](https://tools.ietf.org/html/rfc3924):
> Lawful intercept is the lawfully authorized interception and monitoring of communications of an intercept subject. The term "intercept subject" [...] refers to the subscriber of a telecommunications service whose communications and/or intercept related information (IRI) has been lawfully authorized to be intercepted and delivered to some agency.
### Prison Pay Phones [🔎 →](https://www.shodan.io/search?query=%22%5B2J%5BH+Encartele+Confidential%22)
```plaintext
"[2J[H Encartele Confidential"
```
### [Tesla PowerPack](https://www.tesla.com/powerpack) Charging Status [🔎 →](https://www.shodan.io/search?query=http.title%3A%22Tesla+PowerPack+System%22+http.component%3A%22d3%22+-ga3ca4f2)
```plaintext
http.title:"Tesla PowerPack System" http.component:"d3" -ga3ca4f2
```
<img
src="/static/images/notes/shodan-search-queries/tesla.png"
width="865"
height="543"
alt="Example: Tesla PowerPack Charging Status"
/>
### Electric Vehicle Chargers [🔎 →](https://www.shodan.io/search?query=%22Server%3A+gSOAP%2F2.8%22+%22Content-Length%3A+583%22)
```plaintext
"Server: gSOAP/2.8" "Content-Length: 583"
```
### Maritime Satellites [🔎 →](https://www.shodan.io/search?query=%22Cobham+SATCOM%22+OR+%28%22Sailor%22+%22VSAT%22%29)
Shodan made a pretty sweet [Ship Tracker](https://shiptracker.shodan.io/) that maps ship locations in real time, too!
```plaintext
"Cobham SATCOM" OR ("Sailor" "VSAT")
```
<img
className="center"
src="/static/images/notes/shodan-search-queries/sailor-vsat.png"
width="700"
height="361"
alt="Example: Maritime Satellites"
/>
### Submarine Mission Control Dashboards [🔎 →](https://www.shodan.io/search?query=title%3A%22Slocum+Fleet+Mission+Control%22)
```plaintext
title:"Slocum Fleet Mission Control"
```
### [CAREL PlantVisor](https://www.carel.com/product/plantvisor) Refrigeration Units [🔎 →](https://www.shodan.io/search?query=%22Server%3A+CarelDataServer%22+%22200+Document+follows%22)
```plaintext
"Server: CarelDataServer" "200 Document follows"
```
<img
src="/static/images/notes/shodan-search-queries/refrigeration.png"
width="865"
height="456"
alt="Example: CAREL PlantVisor Refrigeration Units"
/>
### [Nordex Wind Turbine](https://www.nordex-online.com/en/products-services/wind-turbines.html) Farms [🔎 →](https://www.shodan.io/search?query=http.title%3A%22Nordex+Control%22+%22Windows+2000+5.0+x86%22+%22Jetty%2F3.1+%28JSP+1.1%3B+Servlet+2.2%3B+java+1.6.0_14%29%22)
```plaintext
http.title:"Nordex Control" "Windows 2000 5.0 x86" "Jetty/3.1 (JSP 1.1; Servlet 2.2; java 1.6.0_14)"
```
### [C4 Max](https://www.mobile-devices.com/our-products/c4-max/) Commercial Vehicle GPS Trackers [🔎 →](https://www.shodan.io/search?query=%22%5B1m%5B35mWelcome+on+console%22)
```plaintext
"[1m[35mWelcome on console"
```
<img
src="/static/images/notes/shodan-search-queries/c4max.png"
width="865"
height="171"
alt="Example: C4 Max Vehicle GPS"
/>
### [DICOM](https://www.dicomstandard.org/about/) Medical X-Ray Machines [🔎 →](https://www.shodan.io/search?query=%22DICOM+Server+Response%22+port%3A104)
Secured by default, thankfully, but these 1,700+ machines still [have no business](https://documents.trendmicro.com/assets/rpt/rpt-securing-connected-hospitals.pdf) being on the internet.
```plaintext
"DICOM Server Response" port:104
```
### [GaugeTech](https://electroind.com/all-products/) Electricity Meters [🔎 →](https://www.shodan.io/search?query=%22Server%3A+EIG+Embedded+Web+Server%22+%22200+Document+follows%22)
```plaintext
"Server: EIG Embedded Web Server" "200 Document follows"
```
<img
className="center"
src="/static/images/notes/shodan-search-queries/power-gaugetech.png"
width="500"
height="246"
alt="Example: GaugeTech Electricity Meters"
/>
### Siemens Industrial Automation [🔎 →](https://www.shodan.io/search?query=%22Siemens%2C+SIMATIC%22+port%3A161)
```plaintext
"Siemens, SIMATIC" port:161
```
### Siemens HVAC Controllers [🔎 →](https://www.shodan.io/search?query=%22Server%3A+Microsoft-WinCE%22+%22Content-Length%3A+12581%22)
```plaintext
"Server: Microsoft-WinCE" "Content-Length: 12581"
```
### Door / Lock Access Controllers [🔎 →](https://www.shodan.io/search?query=%22HID+VertX%22+port%3A4070)
```plaintext
"HID VertX" port:4070
```
### Railroad Management [🔎 →](https://www.shodan.io/search?query=%22log+off%22+%22select+the+appropriate%22)
```plaintext
"log off" "select the appropriate"
```
---
## Remote Desktop
### Unprotected VNC [🔎 →](https://www.shodan.io/search?query=%22authentication+disabled%22+%22RFB+003.008%22)
```plaintext
"authentication disabled" "RFB 003.008"
```
[Shodan Images](https://images.shodan.io/) is a great supplementary tool to browse screenshots, by the way! [🔎 →](https://images.shodan.io/?query=%22authentication+disabled%22+%21screenshot.label%3Ablank)
<figure>
<img
className="center"
src="/static/images/notes/shodan-search-queries/vnc.png"
width="500"
height="375"
alt="The first result right now. 😞"
/>
<figcaption>The first result right now. 😞</figcaption>
</figure>
### Windows RDP [🔎 →](https://www.shodan.io/search?query=%22%5Cx03%5Cx00%5Cx00%5Cx0b%5Cx06%5Cxd0%5Cx00%5Cx00%5Cx124%5Cx00%22)
99.99% are secured by a secondary Windows login screen.
```plaintext
"\x03\x00\x00\x0b\x06\xd0\x00\x00\x124\x00"
```
---
## Network Infrastructure
### [Weave Scope](https://www.weave.works/oss/scope/) Dashboards [🔎 →](https://www.shodan.io/search?query=title%3A%22Weave+Scope%22+http.favicon.hash%3A567176827)
Command-line access inside Kubernetes pods and Docker containers, and real-time visualization/monitoring of the entire infrastructure.
```plaintext
title:"Weave Scope" http.favicon.hash:567176827
```
<img
src="/static/images/notes/shodan-search-queries/weavescope.png"
width="865"
height="465"
alt="Example: Weave Scope Dashboards"
/>
### MongoDB [🔎 →](https://www.shodan.io/search?query=product%3AMongoDB+-authentication)
Older versions were insecure by default. [Very scary.](https://krebsonsecurity.com/tag/mongodb/)
```plaintext
"MongoDB Server Information" port:27017 -authentication
```
<img
className="center"
src="/static/images/notes/shodan-search-queries/mongo.png"
width="500"
height="238"
alt="Example: MongoDB"
/>
### [Mongo Express](https://github.com/mongo-express/mongo-express) Web GUI [🔎 →](https://www.shodan.io/search?query=%22Set-Cookie%3A+mongo-express%3D%22+%22200+OK%22)
Like the [infamous phpMyAdmin](https://www.cvedetails.com/vulnerability-list/vendor_id-784/Phpmyadmin.html) but for MongoDB.
```plaintext
"Set-Cookie: mongo-express=" "200 OK"
```
<img
className="center"
src="/static/images/notes/shodan-search-queries/mongo-express.png"
width="700"
height="395"
alt="Example: Mongo Express GUI"
/>
### Jenkins CI [🔎 →](https://www.shodan.io/search?query=%22X-Jenkins%22+%22Set-Cookie%3A+JSESSIONID%22+http.title%3A%22Dashboard%22)
```plaintext
"X-Jenkins" "Set-Cookie: JSESSIONID" http.title:"Dashboard"
```
<img
className="center"
src="/static/images/notes/shodan-search-queries/jenkins.png"
width="700"
height="225"
alt="Example: Jenkins CI"
/>
### Docker APIs [🔎 →](https://www.shodan.io/search?query=%22Docker+Containers%3A%22+port%3A2375)
```plaintext
"Docker Containers:" port:2375
```
### Docker Private Registries [🔎 →](https://www.shodan.io/search?query=%22Docker-Distribution-Api-Version%3A+registry%22+%22200+OK%22+-gitlab)
```plaintext
"Docker-Distribution-Api-Version: registry" "200 OK" -gitlab
```
### [Pi-hole](https://pi-hole.net/) Open DNS Servers [🔎 →](https://www.shodan.io/search?query=%22dnsmasq-pi-hole%22+%22Recursion%3A+enabled%22)
```plaintext
"dnsmasq-pi-hole" "Recursion: enabled"
```
### Already Logged-In as `root` via Telnet [🔎 →](https://www.shodan.io/search?query=%22root%40%22+port%3A23+-login+-password+-name+-Session)
```plaintext
"root@" port:23 -login -password -name -Session
```
### Android Root Bridges [🔎 →](https://www.shodan.io/search?query=%22Android+Debug+Bridge%22+%22Device%22+port%3A5555)
A tangential result of Google's dumb fractured update approach. 🙄 [More information here.](https://medium.com/p/root-bridge-how-thousands-of-internet-connected-android-devices-now-have-no-security-and-are-b46a68cb0f20)
```plaintext
"Android Debug Bridge" "Device" port:5555
```
### Lantronix Serial-to-Ethernet Adapter [Leaking Telnet Passwords](https://www.bleepingcomputer.com/news/security/thousands-of-serial-to-ethernet-devices-leak-telnet-passwords/) [🔎 →](https://www.shodan.io/search?query=Lantronix+password+port%3A30718+-secured)
```plaintext
Lantronix password port:30718 -secured
```
### Citrix Virtual Apps [🔎 →](https://www.shodan.io/search?query=%22Citrix+Applications%3A%22+port%3A1604)
```plaintext
"Citrix Applications:" port:1604
```
<img
className="center"
src="/static/images/notes/shodan-search-queries/citrix.png"
width="700"
height="273"
alt="Example: Citrix Virtual Apps"
/>
### Cisco Smart Install [🔎 →](https://www.shodan.io/search?query=%22smart+install+client+active%22)
[Vulnerable](https://2016.zeronights.ru/wp-content/uploads/2016/12/CiscoSmartInstall.v3.pdf) (kind of "by design," but especially when exposed).
```plaintext
"smart install client active"
```
### PBX IP Phone Gateways [🔎 →](https://www.shodan.io/search?query=PBX+%22gateway+console%22+-password+port%3A23)
```plaintext
PBX "gateway console" -password port:23
```
### [Polycom](https://www.polycom.com/hd-video-conferencing.html) Video Conferencing [🔎 →](https://www.shodan.io/search?query=http.title%3A%22-+Polycom%22+%22Server%3A+lighttpd%22)
```plaintext
http.title:"- Polycom" "Server: lighttpd"
```
Telnet Configuration: [🔎 →](https://www.shodan.io/search?query=%22Polycom+Command+Shell%22+-failed+port%3A23)
```plaintext
"Polycom Command Shell" -failed port:23
```
<img
className="center"
src="/static/images/notes/shodan-search-queries/polycom.png"
width="550"
height="251"
alt="Example: Polycom Video Conferencing"
/>
### [Bomgar Help Desk](https://www.beyondtrust.com/remote-support/integrations) Portal [🔎 →](https://www.shodan.io/search?query=%22Server%3A+Bomgar%22+%22200+OK%22)
```plaintext
"Server: Bomgar" "200 OK"
```
### Intel Active Management [CVE-2017-5689](https://www.exploit-db.com/exploits/43385) [🔎 →](https://www.shodan.io/search?query=%22Intel%28R%29+Active+Management+Technology%22+port%3A623%2C664%2C16992%2C16993%2C16994%2C16995)
```plaintext
"Intel(R) Active Management Technology" port:623,664,16992,16993,16994,16995
```
### HP iLO 4 [CVE-2017-12542](https://nvd.nist.gov/vuln/detail/CVE-2017-12542) [🔎 →](https://www.shodan.io/search?query=HP-ILO-4+%21%22HP-ILO-4%2F2.53%22+%21%22HP-ILO-4%2F2.54%22+%21%22HP-ILO-4%2F2.55%22+%21%22HP-ILO-4%2F2.60%22+%21%22HP-ILO-4%2F2.61%22+%21%22HP-ILO-4%2F2.62%22+%21%22HP-iLO-4%2F2.70%22+port%3A1900)
```plaintext
HP-ILO-4 !"HP-ILO-4/2.53" !"HP-ILO-4/2.54" !"HP-ILO-4/2.55" !"HP-ILO-4/2.60" !"HP-ILO-4/2.61" !"HP-ILO-4/2.62" !"HP-iLO-4/2.70" port:1900
```
### Outlook Web Access:
#### Exchange 2007 [🔎 →](https://www.shodan.io/search?query=%22x-owa-version%22+%22IE%3DEmulateIE7%22+%22Server%3A+Microsoft-IIS%2F7.0%22)
```plaintext
"x-owa-version" "IE=EmulateIE7" "Server: Microsoft-IIS/7.0"
```
<img
className="center"
src="/static/images/notes/shodan-search-queries/owa2007.png"
width="450"
height="494"
alt="Example: OWA for Exchange 2007"
/>
#### Exchange 2010 [🔎 →](https://www.shodan.io/search?query=%22x-owa-version%22+%22IE%3DEmulateIE7%22+http.favicon.hash%3A442749392)
```plaintext
"x-owa-version" "IE=EmulateIE7" http.favicon.hash:442749392
```
<img
className="center"
src="/static/images/notes/shodan-search-queries/owa2010.png"
width="450"
height="429"
alt="Example: OWA for Exchange 2010"
/>
#### Exchange 2013 / 2016 [🔎 →](https://www.shodan.io/search?query=%22X-AspNet-Version%22+http.title%3A%22Outlook%22+-%22x-owa-version%22)
```plaintext
"X-AspNet-Version" http.title:"Outlook" -"x-owa-version"
```
<img
className="center"
src="/static/images/notes/shodan-search-queries/owa2013.png"
width="580"
height="230"
alt="Example: OWA for Exchange 2013/2016"
/>
### Lync / Skype for Business [🔎 →](https://www.shodan.io/search?query=%22X-MS-Server-Fqdn%22)
```plaintext
"X-MS-Server-Fqdn"
```
---
## Network Attached Storage (NAS)
### SMB (Samba) File Shares [🔎 →](https://www.shodan.io/search?query=%22Authentication%3A+disabled%22+port%3A445)
Produces ~500,000 results...narrow down by adding "Documents" or "Videos", etc.
```plaintext
"Authentication: disabled" port:445
```
Specifically domain controllers: [🔎 →](https://www.shodan.io/search?query=%22Authentication%3A+disabled%22+NETLOGON+SYSVOL+-unix+port%3A445)
```plaintext
"Authentication: disabled" NETLOGON SYSVOL -unix port:445
```
Concerning [default network shares of QuickBooks](https://quickbooks.intuit.com/learn-support/en-us/help-articles/set-up-folder-and-windows-access-permissions-to-share-company/01/201880) files: [🔎 →](https://www.shodan.io/search?query=%22Authentication%3A+disabled%22+%22Shared+this+folder+to+access+QuickBooks+files+OverNetwork%22+-unix+port%3A445)
```plaintext
"Authentication: disabled" "Shared this folder to access QuickBooks files OverNetwork" -unix port:445
```
### FTP Servers with Anonymous Login [🔎 →](https://www.shodan.io/search?query=%22220%22+%22230+Login+successful.%22+port%3A21)
```plaintext
"220" "230 Login successful." port:21
```
### Iomega / LenovoEMC NAS Drives [🔎 →](https://www.shodan.io/search?query=%22Set-Cookie%3A+iomega%3D%22+-%22manage%2Flogin.html%22+-http.title%3A%22Log+In%22)
```plaintext
"Set-Cookie: iomega=" -"manage/login.html" -http.title:"Log In"
```
<img
className="center"
src="/static/images/notes/shodan-search-queries/iomega.png"
width="600"
height="215"
alt="Example: Iomega / LenovoEMC NAS Drives"
/>
### Buffalo TeraStation NAS Drives [🔎 →](https://www.shodan.io/search?query=Redirecting+sencha+port%3A9000)
```plaintext
Redirecting sencha port:9000
```
<img
className="center"
src="/static/images/notes/shodan-search-queries/buffalo.png"
width="580"
height="140"
alt="Example: Buffalo TeraStation NAS Drives"
/>
### Logitech Media Servers [🔎 →](https://www.shodan.io/search?query=%22Server%3A+Logitech+Media+Server%22+%22200+OK%22)
```plaintext
"Server: Logitech Media Server" "200 OK"
```
<img
className="center"
src="/static/images/notes/shodan-search-queries/logitech.png"
width="500"
height="224"
alt="Example: Logitech Media Servers"
/>
### [Plex](https://www.plex.tv/) Media Servers [🔎 →](https://www.shodan.io/search?query=%22X-Plex-Protocol%22+%22200+OK%22+port%3A32400)
```plaintext
"X-Plex-Protocol" "200 OK" port:32400
```
### [Tautulli / PlexPy](https://github.com/Tautulli/Tautulli) Dashboards [🔎 →](https://www.shodan.io/search?query=%22CherryPy%2F5.1.0%22+%22%2Fhome%22)
```plaintext
"CherryPy/5.1.0" "/home"
```
<img
className="center"
src="/static/images/notes/shodan-search-queries/plexpy.png"
width="560"
height="266"
alt="Example: PlexPy / Tautulli Dashboards"
/>
---
## Webcams
Example images not necessary. 🤦
### Yawcams [🔎 →](https://www.shodan.io/search?query=%22Server%3A+yawcam%22+%22Mime-Type%3A+text%2Fhtml%22)
```plaintext
"Server: yawcam" "Mime-Type: text/html"
```
### webcamXP/webcam7 [🔎 →](https://www.shodan.io/search?query=%28%22webcam+7%22+OR+%22webcamXP%22%29+http.component%3A%22mootools%22+-401)
```plaintext
("webcam 7" OR "webcamXP") http.component:"mootools" -401
```
### Android IP Webcam Server [🔎 →](https://www.shodan.io/search?query=%22Server%3A+IP+Webcam+Server%22+%22200+OK%22)
```plaintext
"Server: IP Webcam Server" "200 OK"
```
### Security DVRs [🔎 →](https://www.shodan.io/search?query=html%3A%22DVR_H264+ActiveX%22)
```plaintext
html:"DVR_H264 ActiveX"
```
---
## Printers & Copiers
### HP Printers [🔎 →](https://www.shodan.io/search?query=%22Serial+Number%3A%22+%22Built%3A%22+%22Server%3A+HP+HTTP%22)
```plaintext
"Serial Number:" "Built:" "Server: HP HTTP"
```
<img
className="center"
src="/static/images/notes/shodan-search-queries/hp.png"
width="700"
height="272"
alt="Example: HP Printers"
/>
### Xerox Copiers/Printers [🔎 →](https://www.shodan.io/search?query=ssl%3A%22Xerox+Generic+Root%22)
```plaintext
ssl:"Xerox Generic Root"
```
<img
className="center"
src="/static/images/notes/shodan-search-queries/xerox.png"
width="620"
height="263"
alt="Example: Xerox Copiers/Printers"
/>
### Epson Printers [🔎 →](https://www.shodan.io/search?query=%22SERVER%3A+EPSON_Linux+UPnP%22+%22200+OK%22)
```plaintext
"SERVER: EPSON_Linux UPnP" "200 OK"
```
```plaintext
"Server: EPSON-HTTP" "200 OK"
```
<img
className="center"
src="/static/images/notes/shodan-search-queries/epson.png"
width="550"
height="308"
alt="Example: Epson Printers"
/>
### Canon Printers [🔎 →](https://www.shodan.io/search?query=%22Server%3A+KS_HTTP%22+%22200+OK%22)
```plaintext
"Server: KS_HTTP" "200 OK"
```
```plaintext
"Server: CANON HTTP Server"
```
<img
className="center"
src="/static/images/notes/shodan-search-queries/canon.png"
width="550"
height="195"
alt="Example: Canon Printers"
/>
---
## Home Devices
### Yamaha Stereos [🔎 →](https://www.shodan.io/search?query=%22Server%3A+AV_Receiver%22+%22HTTP%2F1.1+406%22)
```plaintext
"Server: AV_Receiver" "HTTP/1.1 406"
```
<img
className="center"
src="/static/images/notes/shodan-search-queries/yamaha.png"
width="550"
height="349"
alt="Example: Yamaha Stereos"
/>
### Apple AirPlay Receivers [🔎 →](https://www.shodan.io/search?query=%22%5Cx08_airplay%22+port%3A5353)
Apple TVs, HomePods, etc.
```plaintext
"\x08_airplay" port:5353
```
### Chromecasts / Smart TVs [🔎 →](https://www.shodan.io/search?query=%22Chromecast%3A%22+port%3A8008)
```plaintext
"Chromecast:" port:8008
```
### [Crestron Smart Home](https://www.crestron.com/Products/Market-Solutions/Residential-Solutions) Controllers [🔎 →](https://www.shodan.io/search?query=%22Model%3A+PYNG-HUB%22)
```plaintext
"Model: PYNG-HUB"
```
---
## Random Stuff
### OctoPrint 3D Printer Controllers [🔎 →](https://www.shodan.io/search?query=title%3A%22OctoPrint%22+-title%3A%22Login%22+http.favicon.hash%3A1307375944)
```plaintext
title:"OctoPrint" -title:"Login" http.favicon.hash:1307375944
```
<img
className="center"
src="/static/images/notes/shodan-search-queries/octoprint.png"
width="700"
height="335"
alt="Example: OctoPrint 3D Printers"
/>
### Etherium Miners [🔎 →](https://www.shodan.io/search?query=%22ETH+-+Total+speed%22)
```plaintext
"ETH - Total speed"
```
<img
className="center"
src="/static/images/notes/shodan-search-queries/eth.png"
width="800"
height="141"
alt="Example: Etherium Miners"
/>
### Apache Directory Listings [🔎 →](https://www.shodan.io/search?query=http.title%3A%22Index+of+%2F%22+http.html%3A%22.pem%22)
Substitute `.pem` with any extension or a filename like `phpinfo.php`.
```plaintext
http.title:"Index of /" http.html:".pem"
```
### Misconfigured WordPress [🔎 →](https://www.shodan.io/search?query=http.html%3A%22*+The+wp-config.php+creation+script+uses+this+file%22)
Exposed [`wp-config.php`](https://github.com/WordPress/WordPress/blob/master/wp-config-sample.php) files containing database credentials.
```plaintext
http.html:"* The wp-config.php creation script uses this file"
```
### Too Many Minecraft Servers [🔎 →](https://www.shodan.io/search?query=%22Minecraft+Server%22+%22protocol+340%22+port%3A25565)
```plaintext
"Minecraft Server" "protocol 340" port:25565
```
### Literally [Everything](https://www.vox.com/2014/12/22/7435625/north-korea-internet) in North Korea 🇰🇵 [🔎 →](https://www.shodan.io/search?query=net%3A175.45.176.0%2F22%2C210.52.109.0%2F24)
```plaintext
net:175.45.176.0/22,210.52.109.0/24,77.94.35.0/24
```
### TCP Quote of the Day [🔎 →](https://www.shodan.io/search?query=port%3A17+product%3A%22Windows+qotd%22)
Port 17 ([RFC 865](https://tools.ietf.org/html/rfc865)) has a [bizarre history](https://en.wikipedia.org/wiki/QOTD)...
```plaintext
port:17 product:"Windows qotd"
```
### Find a Job Doing This! 👩‍💼 [🔎 →](https://www.shodan.io/search?query=%22X-Recruiting%3A%22)
```plaintext
"X-Recruiting:"
```
---
If you've found any other juicy Shodan gems, whether it's a search query or a specific example, [open an issue/PR on GitHub!](https://github.com/jakejarvis/awesome-shodan-queries)
Bon voyage, fellow penetrators! 😉

55
notes/y2k-sandbox.mdx Normal file
View File

@ -0,0 +1,55 @@
---
title: "I Made A Thing, Powered by Windows Me™"
date: 2020-06-06 10:05:23-0400
description: "Introducing the Y2K Sandbox: fully featured, fully isolated, on-demand Windows Millennium Edition® virtual machines."
tags:
- Projects
- Nostalgia
- Windows
- Virtual Machines
image: "/static/images/notes/y2k-sandbox/screenshot.png"
---
A few months ago, I stumbled upon [my first website ever](https://jakejarvis.github.io/my-first-website/) on an old floppy disk. Despite the instant cringing, I [uploaded it](https://github.com/jakejarvis/my-first-website) to GitHub, [collected other iterations](/previously/), and made an [#awesome-list](https://github.com/jakejarvis/awesome-first-code) of others who were brave and/or shameless enough to do the same. But why not take that ~~one~~ 1,000 steps further?
Introducing the [**Y2K Sandbox**](https://y2k.app/) — with fully-featured, fully-isolated, on-demand [**Windows Millennium Edition®**](https://www.youtube.com/watch?v=CaNDeyYP98A) virtual machines, simply to experience my first website in its natural Internet Explorer 5 habitat. And maybe play some [3D Pinball: Space Cadet](https://en.wikipedia.org/wiki/Full_Tilt!_Pinball#3D_Pinball_for_Windows_%E2%80%93_Space_Cadet). Oh, and [Microsoft Bob](https://en.wikipedia.org/wiki/Microsoft_Bob) is there too if you want to say hello and catch up. 🤓
<figure>
<a class="no-underline" href="https://y2k.app/" target="_blank" rel="noopener noreferrer">
<img
src="/static/images/notes/y2k-sandbox/screenshot.png"
width="865"
height="649"
alt="Play in the Y2K Sandbox, at your own risk."
/>
</a>
<figcaption>
<a href="https://y2k.app/" target="_blank" rel="noopener noreferrer">
<strong>Play in the Y2K Sandbox, at your own risk.</strong>
</a>
</figcaption>
</figure>
The backend is powered by [**QEMU**](https://www.qemu.org/) (as a Pentium III emulator) inside isolated **Docker** containers, [**websocketd**](https://github.com/joewalnes/websocketd) (an **_awesome_** lightweight WebSockets server written in Go), and [**Cloudflare Tunnels**](https://www.cloudflare.com/products/tunnel/) (for some protection), all tied together with some [Ruby code](https://github.com/jakejarvis/y2k/blob/main/container/bin/boot.rb) and [shell scripts](https://github.com/jakejarvis/y2k/tree/main/host). ~~I'll push the backend scripts up to GitHub once I have a chance to untangle the spaghetti code. 🍝~~
The frontend is _much_ simpler with [a few lines of JavaScript](https://github.com/jakejarvis/y2k/blob/main/frontend/app.js) and [**noVNC**](https://github.com/novnc/noVNC), a VNC-via-WebSockets library, hosted by [**Cloudflare Pages**](https://pages.cloudflare.com/).
### 🎉 Update: [Everything is now on GitHub!](https://github.com/jakejarvis/y2k)
I must give credit to both [charlie.bz](https://charlie.bz/) and [benjojo.co.uk](https://benjojo.co.uk/), similar websites I was enamored with when they were posted on Hacker News a few years ago. Think we'll see some websites like these with Windows 29 in a decade?
<figure>
<img
src="/static/images/notes/y2k-sandbox/windows-me.png"
width="320"
height="92"
alt="@microsoft Please don't sue me."
/>
<figcaption>
<strong>@microsoft</strong> Please don't sue me.
</figcaption>
</figure>
Feel free to [open an issue on GitHub](https://github.com/jakejarvis/y2k/issues) if you run into connection glitches or have any nostalgic inspiration for software you think would be cool to install persistently on the OS image. I certainly can't help with any actual Windows Me crashes, though — it was beyond help a long, long time ago. Like, [the day it came out](https://books.google.com/books?id=Jbft8HXJZwQC&lpg=PP1&pg=PA76#v=onepage&q&f=false). But it will always have a soft spot in my heart.
Anyways... quarantine boredom is a crazy thing, am I right? 😷