Duoling bug report and further improvements
This commit is contained in:
parent
9859c9e5ba
commit
64621d4375
@ -1,6 +1,6 @@
|
|||||||
# My github.io
|
# 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.
|
Will hopefully use it as a portfolio and blog.
|
||||||
How exciting?
|
How exciting?
|
||||||
|
@ -8,18 +8,34 @@ let simple = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let nested = () => {
|
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
|
// Simple helper
|
||||||
Handlebars.registerHelper('', (str) => {
|
Handlebars.registerHelper('censor', (str) => {
|
||||||
return ''
|
return str.replaceAll('fuck', 'f***').replaceAll('hell', 'h***')
|
||||||
})
|
})
|
||||||
|
|
||||||
// Block helper
|
// Block helper
|
||||||
@ -35,14 +51,15 @@ inlinePartial = `
|
|||||||
|
|
||||||
{{/inline}}`
|
{{/inline}}`
|
||||||
|
|
||||||
|
// Calling non-existent partials with block syntax uses the block content as fallback
|
||||||
let advanced = () => {
|
let advanced = () => {
|
||||||
|
return Handlebars.compile(`
|
||||||
|
{{censor profanity}}`)({'profanity': 'fuckin hell man!'})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Run "main" after all is loaded
|
// 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')
|
let output = document.createElement('div')
|
||||||
output.id = 'output'
|
output.id = 'output'
|
||||||
document.getElementById('meta').append(output)
|
document.getElementById('meta').append(output)
|
||||||
@ -54,9 +71,11 @@ document.addEventListener("DOMContentLoaded", function() {
|
|||||||
<h5>Functions:</h5>
|
<h5>Functions:</h5>
|
||||||
<p>Simple: {{{simple}}}</p>
|
<p>Simple: {{{simple}}}</p>
|
||||||
<p>Nested: {{{nested}}}</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
|
// Render and insert the template above
|
||||||
document.getElementById('output').innerHTML = template({
|
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:
|
main:
|
||||||
- name: Blog
|
- name: Blog
|
||||||
url: /blog
|
url: /blog
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
left:
|
||||||
|
- name: Lærling dokumentasjon
|
||||||
|
url: /blog/apprentice
|
||||||
|
weight: 1
|
||||||
main:
|
main:
|
||||||
- name: Blogg
|
- name: Blogg
|
||||||
url: /no/blog
|
url: /no/blog
|
||||||
|
@ -67,8 +67,6 @@ This script is running on this page;
|
|||||||
|
|
||||||
{{< highlight js >}}{{% asset "apprentice/handlebars.js" %}}{{< /highlight >}}
|
{{< highlight js >}}{{% asset "apprentice/handlebars.js" %}}{{< /highlight >}}
|
||||||
|
|
||||||
### Output
|
|
||||||
|
|
||||||
{{< raw >}}
|
{{< raw >}}
|
||||||
<div id='example-out'></div>
|
<div id='example-out'></div>
|
||||||
<!-- <script src='https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.slim.min.js'></script> -->
|
<!-- <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 }}
|
{{ if gt (len .AllTranslations) 1 }}
|
||||||
{{ partial "i18n/nav.html" . }}
|
{{ partial "i18n/nav.html" . }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
<div class='link-group'>
|
|
||||||
{{ $currentPage := . }}
|
{{ $currentPage := . }}
|
||||||
{{ range .Site.Menus.main }}
|
{{ range .Site.Menus.left }}
|
||||||
{{ if .HasChildren }}
|
{{ partial "menu" . }}
|
||||||
<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 }}
|
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
<div class='link-group'>
|
||||||
|
{{ range .Site.Menus.main }}
|
||||||
|
{{ partial "menu" . }}
|
||||||
|
{{ end }}
|
||||||
<!-- <li class='top-nav'><a href='#'>
|
<!-- <li class='top-nav'><a href='#'>
|
||||||
<img class='icons' src='/search-icon.svg'>
|
<img class='icons' src='/search-icon.svg'>
|
||||||
</a>
|
</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>
|
<script src='{{ .RelPermalink }}' integrity='{{ .Data.Integrity }}'></script>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
BIN
static/duolingo-xp-exploit.mp4
Normal file
BIN
static/duolingo-xp-exploit.mp4
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user