Duoling bug report and further improvements
This commit is contained in:
parent
9859c9e5ba
commit
64621d4375
@ -1,6 +1,6 @@
|
||||
# My github.io
|
||||
|
||||
I've converted this page to a hugo generated static webpage.
|
||||
I've converted this page to a [hugo](https://gohugo.io/) generated static webpage.
|
||||
|
||||
Will hopefully use it as a portfolio and blog.
|
||||
How exciting?
|
||||
|
@ -8,18 +8,34 @@ let simple = () => {
|
||||
}
|
||||
|
||||
let nested = () => {
|
||||
|
||||
// This uses each for context switching and uses a nested links parameter
|
||||
let template = Handlebars.compile(`
|
||||
<ul>
|
||||
{{#each links}}
|
||||
<li><a href='{{href}}' target='_blank'>{{text}}</a></li>
|
||||
{{/each}}
|
||||
</ul>`)
|
||||
return template({
|
||||
links: [{
|
||||
'href': 'https://handlebarsjs.com/guide',
|
||||
'text': 'Handlebars official guide'
|
||||
}, {
|
||||
'href': 'https://io.sivert.pw',
|
||||
'text': 'Awesome blog!'
|
||||
}]
|
||||
})
|
||||
}
|
||||
|
||||
let eval = () => {
|
||||
|
||||
}
|
||||
|
||||
|
||||
// This is how handlebars comments work
|
||||
let comments = Handlebars.compile(`
|
||||
{{! This comment will not show up in the output}}
|
||||
<!-- This comment will show up as HTML-comment -->
|
||||
{{!-- This comment may contain mustaches like }} --}}
|
||||
inspect element here!`)()
|
||||
|
||||
// Simple helper
|
||||
Handlebars.registerHelper('', (str) => {
|
||||
return ''
|
||||
Handlebars.registerHelper('censor', (str) => {
|
||||
return str.replaceAll('fuck', 'f***').replaceAll('hell', 'h***')
|
||||
})
|
||||
|
||||
// Block helper
|
||||
@ -35,14 +51,15 @@ inlinePartial = `
|
||||
|
||||
{{/inline}}`
|
||||
|
||||
|
||||
// Calling non-existent partials with block syntax uses the block content as fallback
|
||||
let advanced = () => {
|
||||
|
||||
return Handlebars.compile(`
|
||||
{{censor profanity}}`)({'profanity': 'fuckin hell man!'})
|
||||
}
|
||||
|
||||
|
||||
// Run "main" after all is loaded
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
// Add a output element to the end of the Table of Contents
|
||||
let output = document.createElement('div')
|
||||
output.id = 'output'
|
||||
document.getElementById('meta').append(output)
|
||||
@ -54,9 +71,11 @@ document.addEventListener("DOMContentLoaded", function() {
|
||||
<h5>Functions:</h5>
|
||||
<p>Simple: {{{simple}}}</p>
|
||||
<p>Nested: {{{nested}}}</p>
|
||||
<p>Eval: {{{eval}}}</p></div>`)
|
||||
<p>Comments: {{{comments}}}</p>
|
||||
<p>Advanced: {{{advanced}}}</p></div>`)
|
||||
|
||||
// Render and insert the template above
|
||||
document.getElementById('output').innerHTML = template({
|
||||
simple: simple(), nested: nested(), eval: eval()})
|
||||
simple: simple(), nested: nested(), comments: comments, advanced: advanced()
|
||||
})
|
||||
})
|
||||
|
@ -1,3 +1,7 @@
|
||||
left:
|
||||
- name: Apprentice docs
|
||||
url: /blog/apprentice
|
||||
weight: 1
|
||||
main:
|
||||
- name: Blog
|
||||
url: /blog
|
||||
|
@ -1,3 +1,7 @@
|
||||
left:
|
||||
- name: Lærling dokumentasjon
|
||||
url: /blog/apprentice
|
||||
weight: 1
|
||||
main:
|
||||
- name: Blogg
|
||||
url: /no/blog
|
||||
|
@ -67,8 +67,6 @@ This script is running on this page;
|
||||
|
||||
{{< highlight js >}}{{% asset "apprentice/handlebars.js" %}}{{< /highlight >}}
|
||||
|
||||
### Output
|
||||
|
||||
{{< raw >}}
|
||||
<div id='example-out'></div>
|
||||
<!-- <script src='https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.slim.min.js'></script> -->
|
||||
|
12
content/blog/apprentice/jquery.en.md
Normal file
12
content/blog/apprentice/jquery.en.md
Normal file
@ -0,0 +1,12 @@
|
||||
---
|
||||
date: 2022-06-07T14:42:48Z
|
||||
draft: true
|
||||
aliases: []
|
||||
categories: ['various']
|
||||
series: []
|
||||
tags: ['various']
|
||||
chroma: false
|
||||
toc: true
|
||||
title: Jquery
|
||||
description:
|
||||
---
|
37
content/blog/duolingo-xp-exploit.en.md
Normal file
37
content/blog/duolingo-xp-exploit.en.md
Normal file
@ -0,0 +1,37 @@
|
||||
---
|
||||
date: 2022-06-07T22:11:49Z
|
||||
draft: false
|
||||
aliases: []
|
||||
categories: ['exploit']
|
||||
series: ['hacking']
|
||||
tags: ['bug']
|
||||
chroma: false
|
||||
toc: true
|
||||
title: Duolingo Xp Exploit
|
||||
description: I found a bug in the Duoling app for iOS that let's super/pro users instantly complete speaking only lessons.
|
||||
---
|
||||
|
||||
{{< raw >}}
|
||||
<style>video { float: right; }</style>
|
||||
<video width='27%' autoplay controls loop muted>
|
||||
<source src='/duolingo-xp-exploit.mp4' type='video/mp4'>
|
||||
<b>Your browser does not support the video tag!</b>
|
||||
</video>
|
||||
{{< /raw >}}
|
||||
|
||||
It's possible for super/pro users to instantly complete speaking only lessons on iOS.
|
||||
|
||||
## How to reproduce
|
||||
|
||||
1. Make sure the Duoling app does *not* have microphone access.
|
||||
2. Start a round of "Perfect Pronunciation" in the "Practice Hub".
|
||||
3. Click continue and when prompted for microphone access, just click cancel.
|
||||
4. Profit. (Instant perfect lesson!)
|
||||
|
||||
## Summary
|
||||
The bug here seems to be that the iOS prompt for *possibly* taking the user to the apps permissions in settings, but rather does nothing.
|
||||
Later we do actually get that iOS prompt on the first lesson.
|
||||
The Duoling app skips all the speaking lessons as it usually would when denied microphone access.
|
||||
But this of course is a big problem when all the lessons are speaking lessons.
|
||||
|
||||
The end result is an *almost* instant perfect lesson!~
|
20
layouts/partials/menu.html
Normal file
20
layouts/partials/menu.html
Normal file
@ -0,0 +1,20 @@
|
||||
{{ $currentPage := . }}
|
||||
{{ if .HasChildren }}
|
||||
<li class='{{ if $currentPage.HasMenuCurrent "main" . }}active{{ end }}'>
|
||||
<a href='#'>{{ .Pre }}<span>{{ .Name }}</span></a>
|
||||
</li>
|
||||
<ul class='sub-menu'>
|
||||
{{ range .Children }}
|
||||
<li class='{{ if $currentPage.IsMenuCurrent "main" . }}active{{ end }}'>
|
||||
<a href='{{ .URL }}'>{{ .Name }}</a>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
{{ else }}
|
||||
<li>
|
||||
<a href='{{ .URL }}'>
|
||||
{{ .Pre }}
|
||||
<span>{{ .Name }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{{ end }}
|
@ -4,29 +4,14 @@
|
||||
{{ if gt (len .AllTranslations) 1 }}
|
||||
{{ partial "i18n/nav.html" . }}
|
||||
{{ end }}
|
||||
<div class='link-group'>
|
||||
{{ $currentPage := . }}
|
||||
{{ range .Site.Menus.main }}
|
||||
{{ if .HasChildren }}
|
||||
<li class='{{ if $currentPage.HasMenuCurrent "main" . }}active{{ end }}'>
|
||||
<a href='#'>{{ .Pre }}<span>{{ .Name }}</span></a>
|
||||
</li>
|
||||
<ul class='sub-menu'>
|
||||
{{ range .Children }}
|
||||
<li class='{{ if $currentPage.IsMenuCurrent "main" . }}active{{ end }}'>
|
||||
<a href='{{ .URL }}'>{{ .Name }}</a>
|
||||
</li>
|
||||
{{ end }}
|
||||
</ul>
|
||||
{{ else }}
|
||||
<li>
|
||||
<a href='{{ .URL }}'>
|
||||
{{ .Pre }}
|
||||
<span>{{ .Name }}</span>
|
||||
</a>
|
||||
</li>
|
||||
{{ end }}
|
||||
{{ range .Site.Menus.left }}
|
||||
{{ partial "menu" . }}
|
||||
{{ end }}
|
||||
<div class='link-group'>
|
||||
{{ range .Site.Menus.main }}
|
||||
{{ partial "menu" . }}
|
||||
{{ end }}
|
||||
<!-- <li class='top-nav'><a href='#'>
|
||||
<img class='icons' src='/search-icon.svg'>
|
||||
</a>
|
||||
|
@ -1,3 +1,3 @@
|
||||
{{ with resources.Get (.Get 0) | fingerprint }}
|
||||
{{ with resources.Get (.Get 0) | minify | fingerprint }}
|
||||
<script src='{{ .RelPermalink }}' integrity='{{ .Data.Integrity }}'></script>
|
||||
{{ end }}
|
||||
|
BIN
static/duolingo-xp-exploit.mp4
Normal file
BIN
static/duolingo-xp-exploit.mp4
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user