Copied from my GitHub techdiary
Hacking the web for fun and profit
Now a days javascript and HTML are the assembly language of the web (I first said this in 2012). While still stuff is fun, it’s very brittle because 1) the approach is brittle, and 2) everytime the code changes, which it will everything will break.
- Script Injection
- Console Tricks
- Debugging 101
- Real life examples
- Fly out TOC
- CSS - Styling a web page low level abstraction.
- Bootstrap - A higher level abstraction over css.
- Other resources
Script Injection
Bookmarklets
Turns out you can stick javascript in the address bar, that’s a bookmarklet. Here it is from the way back machine)
Grease Monkey - User Script loader
Called Taper Monkey for chrome, it auto loads a script when you enter a webpage. Useful to personalize websites via css and javascript.
I’m not sure the differences, but I use Voilent Monkey now.
Console Tricks
Load Jquery
You almost always want jquery to play
var jq = document.createElement('script');
jq.src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js";
document.getElementsByTagName('head')[0].appendChild(jq);
// ... give time for script to load, then type (or see below for non wait option)
jQuery.noConflict();
Speed up video playback
document.querySelector("video").playbackRate = 1.25
document.querySelector("video").play()
document.querySelector("video").pause()
Debugging 101
Chrome Keyboard shortcuts
https://developers.google.com/web/tools/chrome-devtools/shortcuts
Key | Command |
---|---|
C-S-I | Enter dev tools |
C-S-M | Toggle Mobile Emulator |
C-S-R | Hard reload (breaking cache) |
C-S-P | Command Pallette (super cool) |
Force reloading
Often needed for CSS -
- A) C-S-R
- Network Tab -> Disable caching
Capturing an object for later use
Often there’s a useful object, that’s only available in the closure. You can always assign a refernce on window e.g.
window.foo = foo_from_within_a_closure_found_from_debugging
Black boxing
Event Handlers
Chrome local overrides
Allows you to save a local copy of the source files for editting. To Use
How to use:
- Goto Sources -> Page
- Find your file, right click and save to overrides
Now you can edit your file to your hearts content
Real life examples
Download the Alexa sound recording
Goto page:
https://www.amazon.com/hz/mycd/myx/#/home/alexaPrivacy/activityHistory&custom&1388538769000&1587497019949
Turns out there are audio elements on the page
$("audio")
Normally, the src attribute in the src element would have a src element, which is does not:
<audio id="audio-A32DOYMUN6DTXA:1.0/2020/04/21/14/G090U61091621908/08:16::TNIH_2V.4f0562e5-aff9-48a1-868a-85aa77aac07aZXV/1">
<source id="audioSource-A32DOYMUN6DTXA:1.0/2020/04/21/14/G090U61091621908/08:16::TNIH_2V.4f0562e5-aff9-48a1-868a-85aa77aac07aZXV/1"/>
</audio>
However, when you click on the play button src attribute appears on the source element:
<audio id="audio-A32DOYMUN6DTXA:1.0/2020/04/21/14/G090U61091621908/08:16::TNIH_2V.4f0562e5-aff9-48a1-868a-85aa77aac07aZXV/1">
<source id="audioSource-A32DOYMUN6DTXA:1.0/2020/04/21/14/G090U61091621908/08:16::TNIH_2V.4f0562e5-aff9-48a1-868a-85aa77aac07aZXV/1"
src="https://www.amazon.com/hz/mycd/playOption?id=A32DOYMUN6DTXA:1.0/2020/04/21/14/G090U61091621908/08:16::TNIH_2V.4f0562e5-aff9-48a1-868a-85aa77aac07aZXV/1">
</audio>
And luckily, the “src” is encoding in the audio source id. Let’s pull those out:
https://www.amazon.com/hz/mycd/playOption?id=
So
$("audio source").each((i,e)=> console.log($(e).attr("id").replace("audioSource-","")))
And lets prepend the download URL
https://www.amazon.com/hz/mycd/playOption?id=A3S5BH2HU6VAYF:1.0/2020/04/21/19/G090LF1175130LD2/23:09::TNIH_2V.252ac310-314c-48e4-b433-749bdb9e8b5eZXV/0
<audio
id="audio-A32DOYMUN6DTXA:1.0/2020/04/21/14/G090U61091621908/08:16::TNIH_2V.4f0562e5-aff9-48a1-868a-85aa77aac07aZXV/1"
>
<source
id="audioSource- A32DOYMUN6DTXA:1.0/2020/04/21/14/G090U61091621908/08:16::TNIH_2V.4f0562e5-aff9-48a1-868a-85aa77aac07aZXV/1"
src="https://www.amazon.com/hz/mycd/playOption?id=A32DOYMUN6DTXA:1.0/2020/04/21/14/G090U61091621908/08:16::TNIH_2V.4f0562e5-aff9-48a1-868a-85aa77aac07aZXV/1"
/>
</audio>
Putting it all together.
This is gobboldy gook for most folks, but useful for me to look up later:
let playerPrefix = "https://www.amazon.com/hz/mycd/playOption?id="
function dumpClips() {
// For every entry in the list
$(".mainBox").each((i,e)=> {
var audio_src = $(e).find("audio source").attr("id").replace("audioSource-","");
console.log(playerPrefix+audio_src);
var timeLoc = $(e).find(".subInfo").get(0)
if (timeLoc)
{
console.log(timeLoc.textContent.trim())
}
var textElem = $(e).find(".summaryCss").get(0)
if (textElem)
{
var text = textElem.textContent.trim()
console.log(text);
}
else
{
// console.log("Text not found", e)
}
})
}
function everyTick() {
dumpClips()
$("#nextButton").click()
}
setInterval(everyTick, 5*1000)
Red herrings - but good approaches
Red Herring: Look at source
You could go looking for the code, but don’t bother it’s minified and not required as you can easily execute the code, and interact with the results. However, if you want to chase this path
- Look at what code is downloaded from network and sources tab.
- Prettify source code
- Add breakpoints on source code, or DOM modification events, or callbacks like keyboard or mouse.
Red Herring: Play button doesn’t appear till you open the chevrons:
$(".fa-angle-down").click()
Red Herring: Audio src doesn’t appear till you click the play button:
$(".playButton").click()
Red Herring: Search for a handy JSON blob.
If you’re lucky the JS downlads a data blob, you can check this by going to the network view, and searching for what you’re looking for. In this case, a partial html page was downloaded, which is harder to parse then the DOM (which you can search via JQuery)
Automating todo item creation in omnifocus for web
Too painful - got into some react/redux sync model, gave up
Ominfocus doesn’t supprot APIs, so we need to automate the web.
In omnifocus, you can add a task by pressing the ‘c’ key, which brings up a dialog. We can “hook that”, by setting a breakpoing on global keypress events.
From there, we get into a closure that has an interesting object. Copy that to global scope.
Screen Size Previews
https://www.duplichecker.com/screen-resolution-simulator.php#
Open graph preview Facebook
https://developers.facebook.com/tools/debug/
Web Site Preview Debugger
https://metatags.io/
Kindle Cloud Reader
I own lots of kindle books, and it’s annoying I can’t access them the way I want. I took a look at Kindle Cloud Reader to see if there was a way to get my Kindle Books as HTML.
This was pretty challenging, here’s what I found:
The cloud reader keeps an iframe containing a subset of the book. You can use jquery to extract the content of the iFrame, BUT only a subset of the book is in memory.
If you look in the network panel, you can see individual fragments being downloaded, which is triggered by clicking next or previous page after a few pages. The fragments are used to load/maintain the fragments.
In theory if we can download all fragments you can load the whole book into the iFrame. This was much easier said then done as the code was obfuscicated, and that broke lots of the normal chrome debugging tools.
I found a a global logging object, I connected it to console.log to see what developers see.
KindleDebug.log = console.log
I then spent a bunch of time try to figure out where the fragments were getting selected. It was super hard due to the anti-debuggin measures. Finally I found:
loadNextPages() loadFragmentsForRange()
I realized I can change the position range for loadFragmentsForRange(). Changing it didn’t always result in more content in the iFrame, so I needed a way to automate it. In theory I could change the obfucated source code, but Chrome’s workspace/local copy wasn’t working (not sure why), so I used a logpoint (a breakpoint that logs) to modify the fragment range. With this, it worked!
Hooray.
Fly out TOC
I started by trying to create this myself, but as with most “build” vs “buy”, you’re better off stealing and buying. Looks like this exists in:
CSS
- Foundation - called magellon
- Bootstrap - called scroll spy
Javscript Reverse Engineering Fly out TOC
Looks like the CSS needs to have the data setup correctly. I found some javascript to do this in hackmd, and started putzing with it. Looks like that gets me the DOM in the form I need.
CSS - Styling a web page low level abstraction.
CSS is stying for the web. CSS is very complex. I recommend using a higher level framework like Bootstrap in general, however abstractions are leaky so you also need to understand some core CSS concepts.
CSS selectors
I always forget these, but it matters as that’s how you select elements in jquery
A full summary, below are some I often use.
- $(.class)
- $(#id)
- $(element) #e.g. h1
When nesting selectors here are the operators
- space - decendant at any level
-
- immediate decendant
-
-
- Adjecent (e.g. sibling)
-
- ~ - Not Adjecent (e.g. not sibling)
Bootstrap - A higher level abstraction over css.
If you’re using styles directly, you’re probably doing it wrong. Bootstrap is designed to handle different operations at different view ports, very helpful. For example, you can hide an element if you’re not on an extra large screen.