Compare commits

..

No commits in common. 'docs' and 'gh-pages' have entirely different histories.

  1. 8
      .gitignore
  2. 3
      .gitmodules
  3. 13
      LICENSE
  4. 58
      README.md
  5. BIN
      assets/images/favicon.png
  6. 20
      assets/images/icons/bitbucket.4ebea66e.svg
  7. 18
      assets/images/icons/github.a4034fb1.svg
  8. 38
      assets/images/icons/gitlab.348cdb3a.svg
  9. 1
      assets/javascripts/application.0cf9b500.js
  10. 1
      assets/javascripts/lunr/lunr.da.js
  11. 1
      assets/javascripts/lunr/lunr.de.js
  12. 1
      assets/javascripts/lunr/lunr.du.js
  13. 1
      assets/javascripts/lunr/lunr.es.js
  14. 1
      assets/javascripts/lunr/lunr.fi.js
  15. 1
      assets/javascripts/lunr/lunr.fr.js
  16. 1
      assets/javascripts/lunr/lunr.hu.js
  17. 1
      assets/javascripts/lunr/lunr.it.js
  18. 1
      assets/javascripts/lunr/lunr.jp.js
  19. 1
      assets/javascripts/lunr/lunr.multi.js
  20. 1
      assets/javascripts/lunr/lunr.no.js
  21. 1
      assets/javascripts/lunr/lunr.pt.js
  22. 1
      assets/javascripts/lunr/lunr.ro.js
  23. 1
      assets/javascripts/lunr/lunr.ru.js
  24. 1
      assets/javascripts/lunr/lunr.stemmer.support.js
  25. 1
      assets/javascripts/lunr/lunr.sv.js
  26. 1
      assets/javascripts/lunr/lunr.tr.js
  27. 1
      assets/javascripts/lunr/tinyseg.js
  28. 1
      assets/javascripts/modernizr.1aa3b519.js
  29. 2
      assets/stylesheets/application-palette.6079476c.css
  30. 2
      assets/stylesheets/application.8d40d89b.css
  31. 7
      css/custom.css
  32. 542
      custom_domains/index.html
  33. 33
      docs/custom_domains.md
  34. 174
      docs/flask.md
  35. 25
      docs/flask_auth_github.md
  36. 22
      docs/flask_auth_org.md
  37. 27
      docs/flask_auth_other.md
  38. 64
      docs/flask_auth_portions.md
  39. 98
      docs/flask_heroku.md
  40. 42
      docs/flask_local.md
  41. 57
      docs/github.md
  42. 67
      docs/heroku.md
  43. 92
      docs/index.md
  44. 110
      docs/repo.md
  45. 676
      flask/index.html
  46. 550
      flask_auth_github/index.html
  47. 549
      flask_auth_org/index.html
  48. 551
      flask_auth_other/index.html
  49. 586
      flask_auth_portions/index.html
  50. 708
      flask_heroku/index.html
  51. 605
      flask_local/index.html
  52. 656
      github/index.html
  53. 676
      heroku/index.html
  54. 0
      img/bunny.png
  55. 0
      img/warnico.png
  56. 0
      img/warning.png
  57. 703
      index.html
  58. 1
      mkdocs-material
  59. 50
      mkdocs.yml
  60. 676
      repo/index.html
  61. 7
      search/lunr.min.js
  62. 1
      search/mustache.min.js
  63. 36
      search/require.js
  64. 4
      search/search-results-template.mustache
  65. 92
      search/search.js
  66. 229
      search/search_index.json
  67. 390
      search/text.js
  68. 96
      sitemap.xml

8
.gitignore vendored

@ -1,8 +0,0 @@ @@ -1,8 +0,0 @@
# ignore mkdocs output/gh-pages branch
site/
# ignore secret branch
secret/
# ignore any makefiles
Makefile

3
.gitmodules vendored

@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
[submodule "mkdocs-material"]
path = mkdocs-material
url = https://git.charlesreid1.com/charlesreid1/mkdocs-material.git

13
LICENSE

@ -1,13 +0,0 @@ @@ -1,13 +0,0 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 458.835.16.92, May 2018
Copyright (C) 2018 Charles Reid <charles@charlesreid1.com>
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

58
README.md

@ -1,58 +0,0 @@ @@ -1,58 +0,0 @@
# github-heroku-attack-rabbits
## What's this business all about, then?
This repository helps you protect your secret pages by (deep breath):
hosting your secret page of static and/or dynamic content using a free Heroku app
running a Python Flask server that uses Flask-Dance to authenticate visitors
with Github which allows you fine-grained access control over your pages based on
user attributes like organization or team membership or even things like how many
repositories a user has or how many vowels are in their username.
Also, did I mention the attack rabbits?
![warning: attack rabbits ahead](docs/img/warning.png)
## Where is everything?
Final pages:
* The finished product (pages on Heroku protected by attack rabbits)
is at [github-heroku-attack-rabbits.herokuapp.com](https://github-heroku-attack-rabbits.herokuapp.com)
* The documentation is at [pages.charlesreid1.com/github-heroku-attack-rabbits](https://pages.charlesreid1.com/github-heroku-attack-rabbits)
Two branches in this repo compose the github-heroku-attack-rabbits documentation:
* (**YOU ARE HERE**) The [docs](https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/docs) branch
contains the files needed to generate the
[github-heroku-attack-rabbits documentation site](https://pages.charlesreid1.com/github-heroku-attack-rabbits).
* The [gh-pages](https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/gh-pages) branch
contains the static files generated from the documentation.
The contents of this branch compose the
[github-heroku-attack-rabbits documentation site](https://pages.charlesreid1.com/github-heroku-attack-rabbits).
Two branches illustrate github-heroku-attack-rabbits in practice:
* The [secret](https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/secret) branch contains the files needed to create the secret page.
This repository is public, so obviously these aren't *actually* secret,
but in practice this would be in a protected repository.
* The [heroku-pages](https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/heroku-pages) branch
contains the content that is actually pushed to Heroku - that is,
the final Flask app.
## Where do I start?
See the [documentation](https://pages.charlesreid1.com/github-heroku-attack-rabbits)
or [docs/index.md](docs/index.md).
## License
This is released under the [WTFPL](LICENSE).

BIN
assets/images/favicon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 B

20
assets/images/icons/bitbucket.4ebea66e.svg

@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
<svg xmlns="http://www.w3.org/2000/svg" width="352" height="448"
viewBox="0 0 352 448" id="bitbucket">
<path fill="currentColor" d="M203.75 214.75q2 15.75-12.625 25.25t-27.875
1.5q-9.75-4.25-13.375-14.5t-0.125-20.5 13-14.5q9-4.5 18.125-3t16 8.875
6.875 16.875zM231.5 209.5q-3.5-26.75-28.25-41t-49.25-3.25q-15.75
7-25.125 22.125t-8.625 32.375q1 22.75 19.375 38.75t41.375 14q22.75-2
38-21t12.5-42zM291.25
74q-5-6.75-14-11.125t-14.5-5.5-17.75-3.125q-72.75-11.75-141.5 0.5-10.75
1.75-16.5 3t-13.75 5.5-12.5 10.75q7.5 7 19 11.375t18.375 5.5 21.875
2.875q57 7.25 112 0.25 15.75-2 22.375-3t18.125-5.375 18.75-11.625zM305.5
332.75q-2 6.5-3.875 19.125t-3.5 21-7.125 17.5-14.5 14.125q-21.5
12-47.375 17.875t-50.5 5.5-50.375-4.625q-11.5-2-20.375-4.5t-19.125-6.75-18.25-10.875-13-15.375q-6.25-24-14.25-73l1.5-4
4.5-2.25q55.75 37 126.625 37t126.875-37q5.25 1.5 6 5.75t-1.25 11.25-2
9.25zM350.75 92.5q-6.5 41.75-27.75 163.75-1.25 7.5-6.75 14t-10.875
10-13.625 7.75q-63 31.5-152.5
22-62-6.75-98.5-34.75-3.75-3-6.375-6.625t-4.25-8.75-2.25-8.5-1.5-9.875-1.375-8.75q-2.25-12.5-6.625-37.5t-7-40.375-5.875-36.875-5.5-39.5q0.75-6.5
4.375-12.125t7.875-9.375 11.25-7.5 11.5-5.625 12-4.625q31.25-11.5
78.25-16 94.75-9.25 169 12.5 38.75 11.5 53.75 30.5 4 5 4.125
12.75t-1.375 13.5z" />
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

18
assets/images/icons/github.a4034fb1.svg

@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
<svg xmlns="http://www.w3.org/2000/svg" width="416" height="448"
viewBox="0 0 416 448" id="github">
<path fill="currentColor" d="M160 304q0 10-3.125 20.5t-10.75 19-18.125
8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19 18.125-8.5
18.125 8.5 10.75 19 3.125 20.5zM320 304q0 10-3.125 20.5t-10.75
19-18.125 8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19
18.125-8.5 18.125 8.5 10.75 19 3.125 20.5zM360
304q0-30-17.25-51t-46.75-21q-10.25 0-48.75 5.25-17.75 2.75-39.25
2.75t-39.25-2.75q-38-5.25-48.75-5.25-29.5 0-46.75 21t-17.25 51q0 22 8
38.375t20.25 25.75 30.5 15 35 7.375 37.25 1.75h42q20.5 0
37.25-1.75t35-7.375 30.5-15 20.25-25.75 8-38.375zM416 260q0 51.75-15.25
82.75-9.5 19.25-26.375 33.25t-35.25 21.5-42.5 11.875-42.875 5.5-41.75
1.125q-19.5 0-35.5-0.75t-36.875-3.125-38.125-7.5-34.25-12.875-30.25-20.25-21.5-28.75q-15.5-30.75-15.5-82.75
0-59.25 34-99-6.75-20.5-6.75-42.5 0-29 12.75-54.5 27 0 47.5 9.875t47.25
30.875q36.75-8.75 77.25-8.75 37 0 70 8 26.25-20.5
46.75-30.25t47.25-9.75q12.75 25.5 12.75 54.5 0 21.75-6.75 42 34 40 34
99.5z" />
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

38
assets/images/icons/gitlab.348cdb3a.svg

@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="500"
viewBox="0 0 500 500" id="gitlab">
<g transform="translate(156.197863, 1.160267)">
<path fill="currentColor"
d="M93.667,473.347L93.667,473.347l90.684-279.097H2.983L93.667,
473.347L93.667,473.347z" />
</g>
<g transform="translate(28.531199, 1.160800)" opacity="0.7">
<path fill="currentColor"
d="M221.333,473.345L130.649,194.25H3.557L221.333,473.345L221.333,
473.345z" />
</g>
<g transform="translate(0.088533, 0.255867)" opacity="0.5">
<path fill="currentColor"
d="M32,195.155L32,195.155L4.441,279.97c-2.513,7.735,0.24,16.21,6.821,
20.99l238.514,173.29 L32,195.155L32,195.155z" />
</g>
<g transform="translate(29.421866, 280.255593)">
<path fill="currentColor"
d="M2.667-84.844h127.092L75.14-252.942c-2.811-8.649-15.047-8.649-17.856,
0L2.667-84.844 L2.667-84.844z" />
</g>
<g transform="translate(247.197860, 1.160800)" opacity="0.7">
<path fill="currentColor"
d="M2.667,473.345L93.351,194.25h127.092L2.667,473.345L2.667,
473.345z" />
</g>
<g transform="translate(246.307061, 0.255867)" opacity="0.5">
<path fill="currentColor"
d="M221.334,195.155L221.334,195.155l27.559,84.815c2.514,7.735-0.24,
16.21-6.821,20.99 L3.557,474.25L221.334,195.155L221.334,195.155z" />
</g>
<g transform="translate(336.973725, 280.255593)">
<path fill="currentColor"
d="M130.667-84.844H3.575l54.618-168.098c2.811-8.649,15.047-8.649,
17.856,0L130.667-84.844 L130.667-84.844z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

1
assets/javascripts/application.0cf9b500.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.da.js

@ -0,0 +1 @@ @@ -0,0 +1 @@
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r,i,n;e.da=function(){this.pipeline.reset(),this.pipeline.add(e.da.trimmer,e.da.stopWordFilter,e.da.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.da.stemmer))},e.da.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.da.trimmer=e.trimmerSupport.generateTrimmer(e.da.wordCharacters),e.Pipeline.registerFunction(e.da.trimmer,"trimmer-da"),e.da.stemmer=(r=e.stemmerSupport.Among,i=e.stemmerSupport.SnowballProgram,n=new function(){var e,n,t,s=[new r("hed",-1,1),new r("ethed",0,1),new r("ered",-1,1),new r("e",-1,1),new r("erede",3,1),new r("ende",3,1),new r("erende",5,1),new r("ene",3,1),new r("erne",3,1),new r("ere",3,1),new r("en",-1,1),new r("heden",10,1),new r("eren",10,1),new r("er",-1,1),new r("heder",13,1),new r("erer",13,1),new r("s",-1,2),new r("heds",16,1),new r("es",16,1),new r("endes",18,1),new r("erendes",19,1),new r("enes",18,1),new r("ernes",18,1),new r("eres",18,1),new r("ens",16,1),new r("hedens",24,1),new r("erens",24,1),new r("ers",16,1),new r("ets",16,1),new r("erets",28,1),new r("et",-1,1),new r("eret",30,1)],o=[new r("gd",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1)],a=[new r("ig",-1,1),new r("lig",0,1),new r("elig",1,1),new r("els",-1,1),new r("løst",-1,2)],d=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],u=[239,254,42,3,0,0,0,0,0,0,0,0,0,0,0,0,16],c=new i;function l(){var e,r=c.limit-c.cursor;c.cursor>=n&&(e=c.limit_backward,c.limit_backward=n,c.ket=c.cursor,c.find_among_b(o,4)?(c.bra=c.cursor,c.limit_backward=e,c.cursor=c.limit-r,c.cursor>c.limit_backward&&(c.cursor--,c.bra=c.cursor,c.slice_del())):c.limit_backward=e)}this.setCurrent=function(e){c.setCurrent(e)},this.getCurrent=function(){return c.getCurrent()},this.stem=function(){var r,i=c.cursor;return function(){var r,i=c.cursor+3;if(n=c.limit,0<=i&&i<=c.limit){for(e=i;;){if(r=c.cursor,c.in_grouping(d,97,248)){c.cursor=r;break}if(c.cursor=r,r>=c.limit)return;c.cursor++}for(;!c.out_grouping(d,97,248);){if(c.cursor>=c.limit)return;c.cursor++}(n=c.cursor)<e&&(n=e)}}(),c.limit_backward=i,c.cursor=c.limit,function(){var e,r;if(c.cursor>=n&&(r=c.limit_backward,c.limit_backward=n,c.ket=c.cursor,e=c.find_among_b(s,32),c.limit_backward=r,e))switch(c.bra=c.cursor,e){case 1:c.slice_del();break;case 2:c.in_grouping_b(u,97,229)&&c.slice_del()}}(),c.cursor=c.limit,l(),c.cursor=c.limit,function(){var e,r,i,t=c.limit-c.cursor;if(c.ket=c.cursor,c.eq_s_b(2,"st")&&(c.bra=c.cursor,c.eq_s_b(2,"ig")&&c.slice_del()),c.cursor=c.limit-t,c.cursor>=n&&(r=c.limit_backward,c.limit_backward=n,c.ket=c.cursor,e=c.find_among_b(a,5),c.limit_backward=r,e))switch(c.bra=c.cursor,e){case 1:c.slice_del(),i=c.limit-c.cursor,l(),c.cursor=c.limit-i;break;case 2:c.slice_from("løs")}}(),c.cursor=c.limit,c.cursor>=n&&(r=c.limit_backward,c.limit_backward=n,c.ket=c.cursor,c.out_grouping_b(d,97,248)?(c.bra=c.cursor,t=c.slice_to(t),c.limit_backward=r,c.eq_v_b(t)&&c.slice_del()):c.limit_backward=r),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return n.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}),e.Pipeline.registerFunction(e.da.stemmer,"stemmer-da"),e.da.stopWordFilter=e.generateStopWordFilter("ad af alle alt anden at blev blive bliver da de dem den denne der deres det dette dig din disse dog du efter eller en end er et for fra ham han hans har havde have hende hendes her hos hun hvad hvis hvor i ikke ind jeg jer jo kunne man mange med meget men mig min mine mit mod ned noget nogle nu når og også om op os over på selv sig sin sine sit skal skulle som sådan thi til ud under var vi vil ville vor være været".split(" ")),e.Pipeline.registerFunction(e.da.stopWordFilter,"stopWordFilter-da")}});

1
assets/javascripts/lunr/lunr.de.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.du.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.es.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.fi.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.fr.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.hu.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.it.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.jp.js

@ -0,0 +1 @@ @@ -0,0 +1 @@
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r="2"==e.version[0];e.jp=function(){this.pipeline.reset(),this.pipeline.add(e.jp.stopWordFilter,e.jp.stemmer),r?this.tokenizer=e.jp.tokenizer:(e.tokenizer&&(e.tokenizer=e.jp.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.jp.tokenizer))};var t=new e.TinySegmenter;e.jp.tokenizer=function(n){if(!arguments.length||null==n||null==n)return[];if(Array.isArray(n))return n.map(function(t){return r?new e.Token(t.toLowerCase()):t.toLowerCase()});for(var i=n.toString().toLowerCase().replace(/^\s+/,""),o=i.length-1;o>=0;o--)if(/\S/.test(i.charAt(o))){i=i.substring(0,o+1);break}return t.segment(i).filter(function(e){return!!e}).map(function(t){return r?new e.Token(t):t})},e.jp.stemmer=function(e){return e},e.Pipeline.registerFunction(e.jp.stemmer,"stemmer-jp"),e.jp.wordCharacters="一二三四五六七八九十百千万億兆一-龠々〆ヵヶぁ-んァ-ヴーア-ン゙a-zA-Za-zA-Z0-90-9",e.jp.stopWordFilter=function(t){if(-1===e.jp.stopWordFilter.stopWords.indexOf(r?t.toString():t))return t},e.jp.stopWordFilter=e.generateStopWordFilter("これ それ あれ この その あの ここ そこ あそこ こちら どこ だれ なに なん 何 私 貴方 貴方方 我々 私達 あの人 あのかた 彼女 彼 です あります おります います は が の に を で え から まで より も どの と し それで しかし".split(" ")),e.Pipeline.registerFunction(e.jp.stopWordFilter,"stopWordFilter-jp")}});

1
assets/javascripts/lunr/lunr.multi.js

@ -0,0 +1 @@ @@ -0,0 +1 @@
!function(e,i){"function"==typeof define&&define.amd?define(i):"object"==typeof exports?module.exports=i():i()(e.lunr)}(this,function(){return function(e){e.multiLanguage=function(){for(var i=Array.prototype.slice.call(arguments),t=i.join("-"),r="",n=[],s=[],p=0;p<i.length;++p)"en"==i[p]?(r+="\\w",n.unshift(e.stopWordFilter),n.push(e.stemmer),s.push(e.stemmer)):(r+=e[i[p]].wordCharacters,n.unshift(e[i[p]].stopWordFilter),n.push(e[i[p]].stemmer),s.push(e[i[p]].stemmer));var o=e.trimmerSupport.generateTrimmer(r);return e.Pipeline.registerFunction(o,"lunr-multi-trimmer-"+t),n.unshift(o),function(){this.pipeline.reset(),this.pipeline.add.apply(this.pipeline,n),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add.apply(this.searchPipeline,s))}}}});

1
assets/javascripts/lunr/lunr.no.js

@ -0,0 +1 @@ @@ -0,0 +1 @@
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r,n,i;e.no=function(){this.pipeline.reset(),this.pipeline.add(e.no.trimmer,e.no.stopWordFilter,e.no.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.no.stemmer))},e.no.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.no.trimmer=e.trimmerSupport.generateTrimmer(e.no.wordCharacters),e.Pipeline.registerFunction(e.no.trimmer,"trimmer-no"),e.no.stemmer=(r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=new function(){var e,i,t=[new r("a",-1,1),new r("e",-1,1),new r("ede",1,1),new r("ande",1,1),new r("ende",1,1),new r("ane",1,1),new r("ene",1,1),new r("hetene",6,1),new r("erte",1,3),new r("en",-1,1),new r("heten",9,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",12,1),new r("s",-1,2),new r("as",14,1),new r("es",14,1),new r("edes",16,1),new r("endes",16,1),new r("enes",16,1),new r("hetenes",19,1),new r("ens",14,1),new r("hetens",21,1),new r("ers",14,1),new r("ets",14,1),new r("et",-1,1),new r("het",25,1),new r("ert",-1,3),new r("ast",-1,1)],o=[new r("dt",-1,-1),new r("vt",-1,-1)],s=[new r("leg",-1,1),new r("eleg",0,1),new r("ig",-1,1),new r("eig",2,1),new r("lig",2,1),new r("elig",4,1),new r("els",-1,1),new r("lov",-1,1),new r("elov",7,1),new r("slov",7,1),new r("hetslov",9,1)],a=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],m=[119,125,149,1],l=new n;this.setCurrent=function(e){l.setCurrent(e)},this.getCurrent=function(){return l.getCurrent()},this.stem=function(){var r,n,u,d,c=l.cursor;return function(){var r,n=l.cursor+3;if(i=l.limit,0<=n||n<=l.limit){for(e=n;;){if(r=l.cursor,l.in_grouping(a,97,248)){l.cursor=r;break}if(r>=l.limit)return;l.cursor=r+1}for(;!l.out_grouping(a,97,248);){if(l.cursor>=l.limit)return;l.cursor++}(i=l.cursor)<e&&(i=e)}}(),l.limit_backward=c,l.cursor=l.limit,function(){var e,r,n;if(l.cursor>=i&&(r=l.limit_backward,l.limit_backward=i,l.ket=l.cursor,e=l.find_among_b(t,29),l.limit_backward=r,e))switch(l.bra=l.cursor,e){case 1:l.slice_del();break;case 2:n=l.limit-l.cursor,l.in_grouping_b(m,98,122)?l.slice_del():(l.cursor=l.limit-n,l.eq_s_b(1,"k")&&l.out_grouping_b(a,97,248)&&l.slice_del());break;case 3:l.slice_from("er")}}(),l.cursor=l.limit,n=l.limit-l.cursor,l.cursor>=i&&(r=l.limit_backward,l.limit_backward=i,l.ket=l.cursor,l.find_among_b(o,2)?(l.bra=l.cursor,l.limit_backward=r,l.cursor=l.limit-n,l.cursor>l.limit_backward&&(l.cursor--,l.bra=l.cursor,l.slice_del())):l.limit_backward=r),l.cursor=l.limit,l.cursor>=i&&(d=l.limit_backward,l.limit_backward=i,l.ket=l.cursor,(u=l.find_among_b(s,11))?(l.bra=l.cursor,l.limit_backward=d,1==u&&l.slice_del()):l.limit_backward=d),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return i.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}),e.Pipeline.registerFunction(e.no.stemmer,"stemmer-no"),e.no.stopWordFilter=e.generateStopWordFilter("alle at av bare begge ble blei bli blir blitt både båe da de deg dei deim deira deires dem den denne der dere deres det dette di din disse ditt du dykk dykkar då eg ein eit eitt eller elles en enn er et ett etter for fordi fra før ha hadde han hans har hennar henne hennes her hjå ho hoe honom hoss hossen hun hva hvem hver hvilke hvilken hvis hvor hvordan hvorfor i ikke ikkje ikkje ingen ingi inkje inn inni ja jeg kan kom korleis korso kun kunne kva kvar kvarhelst kven kvi kvifor man mange me med medan meg meget mellom men mi min mine mitt mot mykje ned no noe noen noka noko nokon nokor nokre nå når og også om opp oss over på samme seg selv si si sia sidan siden sin sine sitt sjøl skal skulle slik so som som somme somt så sånn til um upp ut uten var vart varte ved vere verte vi vil ville vore vors vort vår være være vært å".split(" ")),e.Pipeline.registerFunction(e.no.stopWordFilter,"stopWordFilter-no")}});

1
assets/javascripts/lunr/lunr.pt.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.ro.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.ru.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/lunr.stemmer.support.js

@ -0,0 +1 @@ @@ -0,0 +1 @@
!function(r,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():t()(r.lunr)}(this,function(){return function(r){r.stemmerSupport={Among:function(r,t,i,s){if(this.toCharArray=function(r){for(var t=r.length,i=new Array(t),s=0;s<t;s++)i[s]=r.charCodeAt(s);return i},!r&&""!=r||!t&&0!=t||!i)throw"Bad Among initialisation: s:"+r+", substring_i: "+t+", result: "+i;this.s_size=r.length,this.s=this.toCharArray(r),this.substring_i=t,this.result=i,this.method=s},SnowballProgram:function(){var r;return{bra:0,ket:0,limit:0,cursor:0,limit_backward:0,setCurrent:function(t){r=t,this.cursor=0,this.limit=t.length,this.limit_backward=0,this.bra=this.cursor,this.ket=this.limit},getCurrent:function(){var t=r;return r=null,t},in_grouping:function(t,i,s){if(this.cursor<this.limit){var e=r.charCodeAt(this.cursor);if(e<=s&&e>=i&&t[(e-=i)>>3]&1<<(7&e))return this.cursor++,!0}return!1},in_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e<=s&&e>=i&&t[(e-=i)>>3]&1<<(7&e))return this.cursor--,!0}return!1},out_grouping:function(t,i,s){if(this.cursor<this.limit){var e=r.charCodeAt(this.cursor);if(e>s||e<i)return this.cursor++,!0;if(!(t[(e-=i)>>3]&1<<(7&e)))return this.cursor++,!0}return!1},out_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e>s||e<i)return this.cursor--,!0;if(!(t[(e-=i)>>3]&1<<(7&e)))return this.cursor--,!0}return!1},eq_s:function(t,i){if(this.limit-this.cursor<t)return!1;for(var s=0;s<t;s++)if(r.charCodeAt(this.cursor+s)!=i.charCodeAt(s))return!1;return this.cursor+=t,!0},eq_s_b:function(t,i){if(this.cursor-this.limit_backward<t)return!1;for(var s=0;s<t;s++)if(r.charCodeAt(this.cursor-t+s)!=i.charCodeAt(s))return!1;return this.cursor-=t,!0},find_among:function(t,i){for(var s=0,e=i,n=this.cursor,u=this.limit,o=0,h=0,c=!1;;){for(var a=s+(e-s>>1),f=0,l=o<h?o:h,_=t[a],m=l;m<_.s_size;m++){if(n+l==u){f=-1;break}if(f=r.charCodeAt(n+l)-_.s[m])break;l++}if(f<0?(e=a,h=l):(s=a,o=l),e-s<=1){if(s>0||e==s||c)break;c=!0}}for(;;){if(o>=(_=t[s]).s_size){if(this.cursor=n+_.s_size,!_.method)return _.result;var b=_.method();if(this.cursor=n+_.s_size,b)return _.result}if((s=_.substring_i)<0)return 0}},find_among_b:function(t,i){for(var s=0,e=i,n=this.cursor,u=this.limit_backward,o=0,h=0,c=!1;;){for(var a=s+(e-s>>1),f=0,l=o<h?o:h,_=(m=t[a]).s_size-1-l;_>=0;_--){if(n-l==u){f=-1;break}if(f=r.charCodeAt(n-1-l)-m.s[_])break;l++}if(f<0?(e=a,h=l):(s=a,o=l),e-s<=1){if(s>0||e==s||c)break;c=!0}}for(;;){var m;if(o>=(m=t[s]).s_size){if(this.cursor=n-m.s_size,!m.method)return m.result;var b=m.method();if(this.cursor=n-m.s_size,b)return m.result}if((s=m.substring_i)<0)return 0}},replace_s:function(t,i,s){var e=s.length-(i-t),n=r.substring(0,t),u=r.substring(i);return r=n+s+u,this.limit+=e,this.cursor>=i?this.cursor+=e:this.cursor>t&&(this.cursor=t),e},slice_check:function(){if(this.bra<0||this.bra>this.ket||this.ket>this.limit||this.limit>r.length)throw"faulty slice operation"},slice_from:function(r){this.slice_check(),this.replace_s(this.bra,this.ket,r)},slice_del:function(){this.slice_from("")},insert:function(r,t,i){var s=this.replace_s(r,t,i);r<=this.bra&&(this.bra+=s),r<=this.ket&&(this.ket+=s)},slice_to:function(){return this.slice_check(),r.substring(this.bra,this.ket)},eq_v_b:function(r){return this.eq_s_b(r.length,r)}}}},r.trimmerSupport={generateTrimmer:function(r){var t=new RegExp("^[^"+r+"]+"),i=new RegExp("[^"+r+"]+$");return function(r){return"function"==typeof r.update?r.update(function(r){return r.replace(t,"").replace(i,"")}):r.replace(t,"").replace(i,"")}}}}});

1
assets/javascripts/lunr/lunr.sv.js

@ -0,0 +1 @@ @@ -0,0 +1 @@
!function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r,n,t;e.sv=function(){this.pipeline.reset(),this.pipeline.add(e.sv.trimmer,e.sv.stopWordFilter,e.sv.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.sv.stemmer))},e.sv.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.sv.trimmer=e.trimmerSupport.generateTrimmer(e.sv.wordCharacters),e.Pipeline.registerFunction(e.sv.trimmer,"trimmer-sv"),e.sv.stemmer=(r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,t=new function(){var e,t,i=[new r("a",-1,1),new r("arna",0,1),new r("erna",0,1),new r("heterna",2,1),new r("orna",0,1),new r("ad",-1,1),new r("e",-1,1),new r("ade",6,1),new r("ande",6,1),new r("arne",6,1),new r("are",6,1),new r("aste",6,1),new r("en",-1,1),new r("anden",12,1),new r("aren",12,1),new r("heten",12,1),new r("ern",-1,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",18,1),new r("or",-1,1),new r("s",-1,2),new r("as",21,1),new r("arnas",22,1),new r("ernas",22,1),new r("ornas",22,1),new r("es",21,1),new r("ades",26,1),new r("andes",26,1),new r("ens",21,1),new r("arens",29,1),new r("hetens",29,1),new r("erns",21,1),new r("at",-1,1),new r("andet",-1,1),new r("het",-1,1),new r("ast",-1,1)],s=[new r("dd",-1,-1),new r("gd",-1,-1),new r("nn",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1),new r("tt",-1,-1)],a=[new r("ig",-1,1),new r("lig",0,1),new r("els",-1,1),new r("fullt",-1,3),new r("löst",-1,2)],o=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,24,0,32],u=[119,127,149],m=new n;this.setCurrent=function(e){m.setCurrent(e)},this.getCurrent=function(){return m.getCurrent()},this.stem=function(){var r,n=m.cursor;return function(){var r,n=m.cursor+3;if(t=m.limit,0<=n||n<=m.limit){for(e=n;;){if(r=m.cursor,m.in_grouping(o,97,246)){m.cursor=r;break}if(m.cursor=r,m.cursor>=m.limit)return;m.cursor++}for(;!m.out_grouping(o,97,246);){if(m.cursor>=m.limit)return;m.cursor++}(t=m.cursor)<e&&(t=e)}}(),m.limit_backward=n,m.cursor=m.limit,function(){var e,r=m.limit_backward;if(m.cursor>=t&&(m.limit_backward=t,m.cursor=m.limit,m.ket=m.cursor,e=m.find_among_b(i,37),m.limit_backward=r,e))switch(m.bra=m.cursor,e){case 1:m.slice_del();break;case 2:m.in_grouping_b(u,98,121)&&m.slice_del()}}(),m.cursor=m.limit,r=m.limit_backward,m.cursor>=t&&(m.limit_backward=t,m.cursor=m.limit,m.find_among_b(s,7)&&(m.cursor=m.limit,m.ket=m.cursor,m.cursor>m.limit_backward&&(m.bra=--m.cursor,m.slice_del())),m.limit_backward=r),m.cursor=m.limit,function(){var e,r;if(m.cursor>=t){if(r=m.limit_backward,m.limit_backward=t,m.cursor=m.limit,m.ket=m.cursor,e=m.find_among_b(a,5))switch(m.bra=m.cursor,e){case 1:m.slice_del();break;case 2:m.slice_from("lös");break;case 3:m.slice_from("full")}m.limit_backward=r}}(),!0}},function(e){return"function"==typeof e.update?e.update(function(e){return t.setCurrent(e),t.stem(),t.getCurrent()}):(t.setCurrent(e),t.stem(),t.getCurrent())}),e.Pipeline.registerFunction(e.sv.stemmer,"stemmer-sv"),e.sv.stopWordFilter=e.generateStopWordFilter("alla allt att av blev bli blir blivit de dem den denna deras dess dessa det detta dig din dina ditt du där då efter ej eller en er era ert ett från för ha hade han hans har henne hennes hon honom hur här i icke ingen inom inte jag ju kan kunde man med mellan men mig min mina mitt mot mycket ni nu när någon något några och om oss på samma sedan sig sin sina sitta själv skulle som så sådan sådana sådant till under upp ut utan vad var vara varför varit varje vars vart vem vi vid vilka vilkas vilken vilket vår våra vårt än är åt över".split(" ")),e.Pipeline.registerFunction(e.sv.stopWordFilter,"stopWordFilter-sv")}});

1
assets/javascripts/lunr/lunr.tr.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/lunr/tinyseg.js

File diff suppressed because one or more lines are too long

1
assets/javascripts/modernizr.1aa3b519.js

File diff suppressed because one or more lines are too long

2
assets/stylesheets/application-palette.6079476c.css

File diff suppressed because one or more lines are too long

2
assets/stylesheets/application.8d40d89b.css

File diff suppressed because one or more lines are too long

7
docs/css/custom.css → css/custom.css

@ -5,6 +5,9 @@ div.body { @@ -5,6 +5,9 @@ div.body {
background-color: #efefef;
}
.md-typeset pre {
background-color: #ccc;
background-color: #dedede;
}
div.md-source__icon {
visibility: hidden;
width: 1px;
}

542
custom_domains/index.html

@ -0,0 +1,542 @@ @@ -0,0 +1,542 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<link rel="canonical" href="https://pages.charlesreid1.com/github-heroku-attack-rabbits/custom_domains/">
<meta name="lang:clipboard.copy" content="Copy to clipboard">
<meta name="lang:clipboard.copied" content="Copied to clipboard">
<meta name="lang:search.language" content="en">
<meta name="lang:search.pipeline.stopwords" content="True">
<meta name="lang:search.pipeline.trimmer" content="True">
<meta name="lang:search.result.none" content="No matching documents">
<meta name="lang:search.result.one" content="1 matching document">
<meta name="lang:search.result.other" content="# matching documents">
<meta name="lang:search.tokenizer" content="[\s\-]+">
<link rel="shortcut icon" href="../">
<meta name="generator" content="mkdocs-0.17.3, mkdocs-material-2.7.2">
<title>Custom Domains - github-heroku-attack-rabbits</title>
<link rel="stylesheet" href="../assets/stylesheets/application.8d40d89b.css">
<link rel="stylesheet" href="../assets/stylesheets/application-palette.6079476c.css">
<script src="../assets/javascripts/modernizr.1aa3b519.js"></script>
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Questrial:300,400,400i,700|Roboto+Mono">
<style>body,input{font-family:"Questrial","Helvetica Neue",Helvetica,Arial,sans-serif}code,kbd,pre{font-family:"Roboto Mono","Courier New",Courier,monospace}</style>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="../css/custom.css">
</head>
<body dir="ltr" data-md-color-primary="red" data-md-color-accent="red">
<svg class="md-svg">
<defs>
<svg xmlns="http://www.w3.org/2000/svg" width="416" height="448"
viewBox="0 0 416 448" id="github">
<path fill="currentColor" d="M160 304q0 10-3.125 20.5t-10.75 19-18.125
8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19 18.125-8.5
18.125 8.5 10.75 19 3.125 20.5zM320 304q0 10-3.125 20.5t-10.75
19-18.125 8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19
18.125-8.5 18.125 8.5 10.75 19 3.125 20.5zM360
304q0-30-17.25-51t-46.75-21q-10.25 0-48.75 5.25-17.75 2.75-39.25
2.75t-39.25-2.75q-38-5.25-48.75-5.25-29.5 0-46.75 21t-17.25 51q0 22 8
38.375t20.25 25.75 30.5 15 35 7.375 37.25 1.75h42q20.5 0
37.25-1.75t35-7.375 30.5-15 20.25-25.75 8-38.375zM416 260q0 51.75-15.25
82.75-9.5 19.25-26.375 33.25t-35.25 21.5-42.5 11.875-42.875 5.5-41.75
1.125q-19.5 0-35.5-0.75t-36.875-3.125-38.125-7.5-34.25-12.875-30.25-20.25-21.5-28.75q-15.5-30.75-15.5-82.75
0-59.25 34-99-6.75-20.5-6.75-42.5 0-29 12.75-54.5 27 0 47.5 9.875t47.25
30.875q36.75-8.75 77.25-8.75 37 0 70 8 26.25-20.5
46.75-30.25t47.25-9.75q12.75 25.5 12.75 54.5 0 21.75-6.75 42 34 40 34
99.5z" />
</svg>
</defs>
</svg>
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="search" autocomplete="off">
<label class="md-overlay" data-md-component="overlay" for="drawer"></label>
<a href="#custom-domains" tabindex="1" class="md-skip">
Skip to content
</a>
<header class="md-header" data-md-component="header">
<nav class="md-header-nav md-grid">
<div class="md-flex">
<div class="md-flex__cell md-flex__cell--shrink">
<a href="https://pages.charlesreid1.com/github-heroku-attack-rabbits" title="github-heroku-attack-rabbits" class="md-header-nav__button md-logo">
<img src="../img/bunny.png" width="24" height="24">
</a>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--menu md-header-nav__button" for="drawer"></label>
</div>
<div class="md-flex__cell md-flex__cell--stretch">
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
<span class="md-header-nav__topic">
github-heroku-attack-rabbits
</span>
<span class="md-header-nav__topic">
Custom Domains
</span>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--search md-header-nav__button" for="search"></label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="query" data-md-state="active">
<label class="md-icon md-search__icon" for="search"></label>
<button type="reset" class="md-icon md-search__icon" data-md-component="reset" tabindex="-1">
&#xE5CD;
</button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="result">
<div class="md-search-result__meta">
Type to start searching
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<div class="md-header-nav__source">
<a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
charlesreid1/github-heroku-attack-rabbits
</div>
</a>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container">
<main class="md-main">
<div class="md-main__inner md-grid" data-md-component="container">
<div class="md-sidebar md-sidebar--primary" data-md-component="navigation">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" data-md-level="0">
<label class="md-nav__title md-nav__title--site" for="drawer">
<span class="md-nav__button md-logo">
<img src="../img/bunny.png" width="48" height="48">
</span>
github-heroku-attack-rabbits
</label>
<div class="md-nav__source">
<a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
charlesreid1/github-heroku-attack-rabbits
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href=".." title="Index" class="md-nav__link">
Index
</a>
</li>
<li class="md-nav__item">
<a href="../heroku/" title="Get Started with Heroku" class="md-nav__link">
Get Started with Heroku
</a>
</li>
<li class="md-nav__item">
<a href="../github/" title="Get Started with Github" class="md-nav__link">
Get Started with Github
</a>
</li>
<li class="md-nav__item">
<a href="../repo/" title="Initialize Repository: Branches" class="md-nav__link">
Initialize Repository: Branches
</a>
</li>
<li class="md-nav__item">
<a href="../flask/" title="Create a Flask App using Flask-Dance" class="md-nav__link">
Create a Flask App using Flask-Dance
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-6" type="checkbox" id="nav-6">
<label class="md-nav__link" for="nav-6">
Flask
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-6">
Flask
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../flask_auth_github/" title="Authenticate users based on Github membership only" class="md-nav__link">
Authenticate users based on Github membership only
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_org/" title="Authenticate users based on organization or team membership" class="md-nav__link">
Authenticate users based on organization or team membership
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_other/" title="Authenticate users based on some other criteria" class="md-nav__link">
Authenticate users based on some other criteria
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_portions/" title="Protection portions of the site" class="md-nav__link">
Protection portions of the site
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../flask_local/" title="Test Flask App Locally" class="md-nav__link">
Test Flask App Locally
</a>
</li>
<li class="md-nav__item">
<a href="../flask_heroku/" title="Deploying Flask App to Heroku" class="md-nav__link">
Deploying Flask App to Heroku
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-toggle md-nav__toggle" data-md-toggle="toc" type="checkbox" id="toc">
<a href="./" title="Custom Domains" class="md-nav__link md-nav__link--active">
Custom Domains
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="toc">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary">
</nav>
</div>
</div>
</div>
<div class="md-content">
<article class="md-content__inner md-typeset">
<h1 id="custom-domains">Custom Domains</h1>
<p>If you want to use a custom domain:</p>
<ul>
<li>Set up custom domain using Heroku command line interface</li>
<li>This will set up a DNS subdomain specifically for your app</li>
<li>Point your DNS records to the Heroku DNS subdomain</li>
</ul>
<p>This also introduces complications with HTTP vs HTTPS:
OAuth must happen over HTTPS (required by protocol).
But you the user can control your domain and create
SSL certificates for it, but Heroku is hosting the app.</p>
<p>You have two options: the free option, and the pay option.</p>
<p><strong>The pay option:</strong> For $7/mo you can upgrade to hobby nodes,
which allows you to give Heroku permission to create an SSL
certificate for your domain. This is the easiest solution
and requires zero setup, zero certificate management.</p>
<p><strong>The free option:</strong> You can have your domain (HTTP only)
forward to Heroku (HTTPS can't be forwarded - that's <strong><em>key</em></strong>).
When you hit the Heroku domain, it will log the user in to Github.
When the user logs in successfully, Github will redirect them to
the callback URL. This callback URL <strong><em>MUST</em></strong> be HTTPS, so it cannot
redirect back to your (HTTP-only) custom domain.</p>
<p>That means the userr will, after authenticating with Github,
always be redirected to <code>https://my-cool-app.herokuapp.com</code>
and never <code>http://my-cool-custom-domain-that-cannot-be-used-as-a-callback-because-it-is-https-only.com</code>.</p>
<p>The paid option is much, much simpler in the end
and will save you $7/mo in setup time alone.</p>
</article>
</div>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-nav">
<nav class="md-footer-nav__inner md-grid">
<a href="../flask_heroku/" title="Deploying Flask App to Heroku" class="md-flex md-footer-nav__link md-footer-nav__link--prev" rel="prev">
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-back md-footer-nav__button"></i>
</div>
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Previous
</span>
Deploying Flask App to Heroku
</span>
</div>
</a>
</nav>
</div>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-footer-copyright">
<div class="md-footer-copyright__highlight">
Copyright &copy; 2018 Charles Reid, released under the <a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/docs/LICENSE">WTFPL</a>.<br /><br />Many Bothans died to bring us this documentation.<br /><br />
</div>
powered by
<a href="http://www.mkdocs.org">MkDocs</a>
and
<a href="https://squidfunk.github.io/mkdocs-material/">
Material for MkDocs</a>
</div>
</div>
</div>
</footer>
</div>
<script src="../assets/javascripts/application.0cf9b500.js"></script>
<script>app.initialize({version:"0.17.3",url:{base:".."}})</script>
<script src="../search/require.js"></script>
<script src="../search/search.js"></script>
</body>
</html>

33
docs/custom_domains.md

@ -1,33 +0,0 @@ @@ -1,33 +0,0 @@
# Custom Domains
If you want to use a custom domain:
* Set up custom domain using Heroku command line interface
* This will set up a DNS subdomain specifically for your app
* Point your DNS records to the Heroku DNS subdomain
This also introduces complications with HTTP vs HTTPS:
OAuth must happen over HTTPS (required by protocol).
But you the user can control your domain and create
SSL certificates for it, but Heroku is hosting the app.
You have two options: the free option, and the pay option.
**The pay option:** For $7/mo you can upgrade to hobby nodes,
which allows you to give Heroku permission to create an SSL
certificate for your domain. This is the easiest solution
and requires zero setup, zero certificate management.
**The free option:** You can have your domain (HTTP only)
forward to Heroku (HTTPS can't be forwarded - that's ***key***).
When you hit the Heroku domain, it will log the user in to Github.
When the user logs in successfully, Github will redirect them to
the callback URL. This callback URL ***MUST*** be HTTPS, so it cannot
redirect back to your (HTTP-only) custom domain.
That means the userr will, after authenticating with Github,
always be redirected to `https://my-cool-app.herokuapp.com`
and never `http://my-cool-custom-domain-that-cannot-be-used-as-a-callback-because-it-is-https-only.com`.
The paid option is much, much simpler in the end
and will save you $7/mo in setup time alone.

174
docs/flask.md

@ -1,174 +0,0 @@ @@ -1,174 +0,0 @@
# Create a Flask App using Flask-Dance
This is the heart of the method.
The best thing to do here is just to walk you through the script.
Import statements:
```
import os, json
from os.path import join, isfile, isdir
from werkzeug.contrib.fixers import ProxyFix
from flask import Flask, redirect, url_for, send_from_directory
from flask_dance.contrib.github import make_github_blueprint, github
```
Note that flask-dance adds an OAuth login/callback route
to your Flask app by creating a `/login` blueprint,
meaning all the OAuth stuff is just magically available
via `/login`.
Set paths for static content:
```
PROJECT_ROOT = os.path.dirname(os.path.realpath(__file__))
STATIC_PATH = 'content'
```
Create and configure app. This requires confidential information
for the Github application you created, specifically the client
ID and client secret. These are at the very top of the page when
you visit your app's settings page.
To find this, after you log in, click your profile photo in the
upper right > Settings > Developer Settings > OAuth Apps > click the
name for your OAuth app.
```
app = Flask(__name__)
# this worked locally, but not on heroku
app.wsgi_app = ProxyFix(app.wsgi_app)
app.secret_key = os.environ.get("FLASK_SECRET_KEY", "9502861d41e8729c5cae3225920b1b46")
app.config["RESULT_STATIC_PATH"] = STATIC_PATH #os.path.join(PROJECT_ROOT,STATIC_PATH)
app.config["GITHUB_OAUTH_CLIENT_ID"] = os.environ.get("GITHUB_OAUTH_CLIENT_ID")
app.config["GITHUB_OAUTH_CLIENT_SECRET"] = os.environ.get("GITHUB_OAUTH_CLIENT_SECRET")
```
Now the magic happens: we use flask-dance to create a blueprint
that has methods and settings all ready to go for us to do the
OAuth dance.
`make_github_blueprint()` is part of the contrib module of flask-dance.
There are several similar methods to generate blueprints for
authenticating with other APIs.
```
github_bp = make_github_blueprint(
client_id = os.environ.get('GITHUB_OAUTH_CLIENT_ID'),
client_secret = os.environ.get('GITHUB_OAUTH_CLIENT_SECRET'),
scope='read:org')
app.register_blueprint(github_bp, url_prefix="/login")
contents404 = "<html><body><h1>Status: Error 404 Page Not Found</h1></body></html>"
contents403 = "<html><body><h1>Status: Error 403 Access Denied</h1></body></html>"
contents200 = "<html><body><h1>Status: OK 200</h1></body></html>"
```
Deal with the `/` route first:
* Check if authorized, if not, redirect them to the login URL
(magical URLs taken care of magically by our `make_github_blueprint`
function above)
* If user is authorized (i.e., if they have gone through the OAuth
process and given their passsword to Github and been redirected
to your app with an OAuth token), then the next step is to
find out some information about them.
* Use the `github` object to call the Github API directly.
* Decide what to do from there.
```
@app.route('/')
def index():
if not github.authorized:
return redirect(url_for("github.login"))
resp = github.get("/user/orgs")
if resp.ok:
all_orgs = resp.json()
for org in all_orgs:
if org['login']=='rainbow-mind-machine':
```
The next line is important to how the server works:
if all of the criteria above have been met, we return
a static file:
```
return send_from_directory(STATIC_PATH, 'index.html')
```
This is normally "bad practice," and numerous type A people
on the internet will tell you Flask should not be used for
serving static files, and that you should use nginx etc.,
but these fail to igonore the following:
* Heroku does not let you run or configure nginx
* For crying out loud this example is about attack rabbits
stop taking everything so seriously
Now that we've got that out of the way...
Here's how we serve up static files. This is a total hack,
but it works. It takes any arbitrary path supplied by the
user, and attempts to find a corresponding file to serve up
on disk.
If the user passes a file, then that file is served up.
If the user passes a directory, then `index.html` is served up.
If the user asks for a non-existent file, a 404 error is shown.
If the user is not allowed to view the content, they will face
the bowel-emptying terrors of the 403 error.
```
@app.route('/<path:path>')
def catch_all(path):
if not github.authorized:
return redirect(url_for("github.login"))
username = github.get("/user").json()['login']
rsp = app.config["RESULT_STATIC_PATH"]
resp = github.get("/user/orgs")
if resp.ok:
all_orgs = resp.json()
for org in all_orgs:
if org['login']=='dcppc':
if(path==''):
return send_from_directory(rsp, 'index.html')
elif(isdir(join(rsp,path))):
return send_from_directory(join(rsp,path),'index.html')
elif(isfile(join(rsp,path))):
return send_from_directory(rsp, path)
else:
return contents404
return contents403
```
Last, set a default 404 handler, and run the app:
```
@app.errorhandler(404)
def oops(e):
return contents404
if __name__ == "__main__":
app.run()
```

25
docs/flask_auth_github.md

@ -1,25 +0,0 @@ @@ -1,25 +0,0 @@
# Authenticate Users on Github Membership
For the sake of simplicity, will just demonstrate how this
works for a single route, but you can combine different
rules into multiple routes to provide access to different
people on different parts of a site.
Here is the relevant method that serves up `index.html`
if the user is authenticated:
```
@app.route('/')
def index():
if not github.authorized:
return redirect(url_for("github.login"))
resp = github.get("/user")
if resp.ok:
return send_from_directory(STATIC_PATH, 'index.html')
return contents403
```

22
docs/flask_auth_org.md

@ -1,22 +0,0 @@ @@ -1,22 +0,0 @@
# Authenticate Users on Organization or Team Membership
Here is how we can make access to a given page or route
conditional on membership in an organization (in this
example, membership in the `rainbow-mind-machine` organization
is required for access):
```
@app.route('/')
def index():
if not github.authorized:
return redirect(url_for("github.login"))
resp = github.get("/user/orgs")
if resp.ok:
all_orgs = resp.json()
for org in all_orgs:
if org['login']=='rainbow-mind-machine':
return send_from_directory(STATIC_PATH, 'index.html')
```

27
docs/flask_auth_other.md

@ -1,27 +0,0 @@ @@ -1,27 +0,0 @@
# Authenticate Users on Other Criteria
Suppose we wanted to do something silly like restrict
access to a page to users with Github handles that were
between 5 and 7 letters.
Here is the relevant method that serves up `index.html`
if the user's Github handle is 5-7 letters long:
```
@app.route('/')
def index():
if not github.authorized:
return redirect(url_for("github.login"))
resp = github.get("/user")
if resp.ok:
username = resp.json()['login']
if len(username)>=5 and len(username)<=7:
return send_from_directory(STATIC_PATH, 'index.html')
return contents403
```

64
docs/flask_auth_portions.md

@ -1,64 +0,0 @@ @@ -1,64 +0,0 @@
# Authenticate Different Users on Different Portions of Site
**NOTE: if you are authenticating using membership on a team, you will need the
team id of the team you are interested in authenticating against.**
For this example, let's expand the routes we're looking at
a bit more.
Suppose we have two folders, `team_only` and `org_only`.
The `team_only` folder should only be accessible to your team, `Team Gold`.
The `org_only` folder should only be accessible to your organization, `Colorful Colors`.
The main site (i.e., all other files) should be publicly accessible.
```
@app.route('/')
def index():
return send_from_directory(STATIC_PATH, 'index.html')
@app.route('/team_only/<path:path>')
def team_gold(path):
if not github.authorized:
return redirect(url_for("github.login"))
rsp = app.config["RESULT_STATIC_PATH"]
resp = github.get("/user")
if resp.ok:
username = resp.json()['login']
team_id = 'XXXXX'
resp = github.get("/teams/%s/members/%s"%( team_id, username ))
if resp.code==204:
team_gold_dir = os.path.join(STATIC_PATH, 'team_only')
return send_from_directory(team_gold_dir, 'index.html')
return contents403
@app.route('/org_only/<path:path>')
def team_gold(path):
if not github.authorized:
return redirect(url_for("github.login"))
rsp = app.config["RESULT_STATIC_PATH"]
resp = github.get("/user")
if resp.ok:
my_org = 'XXXXXXXX'
all_orgs = resp.json()
for org in all_orgs:
if org['login']==my_org:
color_org_dir = os.path.join(STATIC_PATH, 'org_only')
return send_from_directory(color_org_dir, 'index.html')
return contents403
```

98
docs/flask_heroku.md

@ -1,98 +0,0 @@ @@ -1,98 +0,0 @@
# Deploying to Heroku
Once we have debugged the Flask app and we are happy with it,
we are ready to deploy it to Heroku.
## Repository Setup
To do this, you should set up your repo as follows:
Clone the repo:
```
$ git clone https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits.git
```
The repo has the following structure:
```
github-heroku-attack-rabbits/
LICENSE
README.md
mkdocs.yml
docs/
index.md
...
mkdocs-material/
...
```
Now, inside the repo, clone the repo again,
but this time clone the `heroku-pages` branch
to the `site/` directory:
```
$ cd github-heroku-attack-rabbits/
$ git clone -b heroku-pages https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits.git site
```
## Heroku Deploy Process
To deploy content to Heroku, we add our Heroku project as a git remote
(see the [heroku](heroku.md) page for how to do that) and then push to
to the master branch of the heroku remote git repo. Changes are pulled
in by Heroku and the app is restarted each time you run `git push`.
We walk through the steps below.
## Heroku Login
From the `site/` directory containing the contents of the `heroku-pages` branch,
that is, containing the Python flask app, log in to Heroku:
```
$ heroku login
```
## Add Heroku Remote to `heroku-pages` Branch
Now have Heroku add the proper git remote address:
```
$ heroku git:remote -a <heroku-app-name>
```
Now you're ready to deploy to Heroku.
## Deploy to Heroku
Double check your app is ready, then deploy:
```
$ git push heroku heroku-pages:master
```
This will push the local branch `heroku-pages` to
the remote branch `master` on the `heroku` remote.
This should begin a pre-commit hook where Heroku
compiles your Python app. You should get the green
light, if you tested your app locally and everything
was good to go.
## Check Your Heroku App
Your Heroku app will be available at
```
https://<heroku-app-name>.herokuapp.com
```
You should see your Python flask app
show up shortly.

42
docs/flask_local.md

@ -1,42 +0,0 @@ @@ -1,42 +0,0 @@
# Testing Flask App Locally
We set up the Github App to use a callback of `https://localhost:5000/login/github/authorized`
so that we could test the app locally. Now it is time to test the app locally.
The application needs access to your Github app id and token. Those are provided
via the `GITHUB_OAUTH_CLIENT_{ID,SECRET}` environment variables. Set these
when you run the actual python command to run the server:
```
$ GITHUB_OAUTH_CLIENT_ID="xxxxxxx" \
GITHUB_OAUTH_CLIENT_SECRET="xxxxxxx" \
OAUTHLIB_INSECURE_TRANSPORT=true \
python github.py
```
This runs the Flask server on port 5000, where it will wait for a visitor.
The way we have our application written in this example, the main `/` route
will redirect the user to a Github login screen immediately, but you could
also present the user with a friendly welcome page when they go to `/`,
and only redirect them to the Github login prompt when they visit a
URL like `/login` or `/auth`.
Once you run the above command, open the following URL in your browser:
```
http://localhost:5000/
```
**NOTE: Make sure you are logged out of Github and that you clear your cookies
if you are already logged in as one user and wish to authenticate as another.
The login is _very_ persistent so you may need to close and re-open your browser.**
Visiting the address above will result in your being redirected to a Github
login page. Once you login, Github will redirect the user back to the
github-heroku-attack-rabbits application with a token that the application
can use to perform actions on behalf of the user.
## Next Step?
If the app works, the next step is to deploy to Heroku.

57
docs/github.md

@ -1,57 +0,0 @@ @@ -1,57 +0,0 @@
## get started with github
We mentioned on the [heroku](heroku.md) page that heroku
creates a remote git repository to hold the files you
want to host.
To use the contents of a Github repository on Heroku,
just treat it like another git remote, no special setup
is needed.
However, to set up your Github-Heroku attack rabbits to
authenticate a user via Github, and mercilessly attack
all intruders, you must create a Github OAuth App.
### Creating Github OAuth App
Log into Github
Go to Settings
Click "Developer Settings" on the left side
Click "New OAuth App" button in upper right
**What do these settings mean?**
* **Application name** is what will be shown to users when they visit
a page protected by the attack rabbits and are prompted for
their password by Github.
* **Homepage URL/Application description** are for users who want to know more
about your killer attack rabbit Github app
* **Authorization callback URL** is the URL that the users will be sent to
once they authenticate with Github and they are granted an OAuth token.
This is the magic ingredient that allows you to take actions on behalf
of the account logging in.
In this guide we'll cover the case of checking membership in organizations or teams,
but what your attack rabbits end up doing to determine if a user is allowed to
access your secret pages is up to you.
## Values to use
You should set your own values for the **name** and **description** fields.
The **home URL** is not actually necessary - it is simply provided for users to
get more information about your app.
The most important is the **callback URL**, which should be set to:
http://localhost:5000/login/github/authorized
This is for testing locally *only*.
Don't use HTTPS in the callback URL!

67
docs/heroku.md

@ -1,67 +0,0 @@ @@ -1,67 +0,0 @@
# create heroku app
### Heroku toolbelt
Heroku offers a really nice command line interface tool called
Heroku Toolbelt. It is available through Homebrew and Aptitude:
```
$ brew install heroku # from Mac
$ apt-get install heroku # from Ubuntu
```
It is then available on the command line as `heroku`.
The first thing you should do is authenticate with
your Heroku account by running
```
$ heroku login
```
We will use this command line application for the following tasks:
* Create a git remote to point to the right Heroku git remote location
* Set environment variables (for e.g. secret keys) on the remote Heroku instance
* Get information (logs, status, etc.) about your Heroku app
We will cover these commands as they come up.
### Create heroku app
Start by creating a heroku app.
* Each heroku app must have a unique name
* Each heroku app creates a remote git repo
* Master branch is what Heroku deploys publicly on herokuapps.com
* You will also need heroku CLI to link your github repo to your heroku app
### Where heroku app lives
Suppose you are creating an app called `my-cool-app`
on heroku. Then your application will be hosted by
Heroku and will be available at the URL:
```
https://my-cool-app.herokuapp.com
```
### How heroku apps works
If you have used Github Pages before, Heroku uses a similar
model (live hosting one particular branch of a git repository).
However, Heroku is different because you can run dynamic scripts
using Python, Ruby, PHP, etc.
To change the content of your Heroku app, just change the contents
of the repository, and push to master (push to the master branch of
the remote Heroku repository).
You will need to structure your repository carefully.
That's what this page is here to help you do.
Heroku can figure out the rest from there.

92
docs/index.md

@ -1,92 +0,0 @@ @@ -1,92 +0,0 @@
# github-heroku-attack-rabbits
## What's this business all about, then?
This repository helps you put access control into place to protect your secret pages by (deep breath):
hosting your secret page of static and/or dynamic content by using a free Heroku app
running a Python Flask server that uses Flask-Dance to authenticate visitors
with Github using OAuth which allows you fine-grained access control for your pages
using user attributes like organization or team membership or even things like how many
vowels a user has in their username.
Also, did I mention the attack rabbits?
![warning: attack rabbits ahead](img/warning.png)
## Where is everything?
Final pages:
* The finished product (pages on Heroku protected by attack rabbits)
is at [github-heroku-attack-rabbits.herokuapp.com](https://github-heroku-attack-rabbits.herokuapp.com)
* The documentation is at [pages.charlesreid1.com/github-heroku-attack-rabbits](https://pages.charlesreid1.com/github-heroku-attack-rabbits)
Two branches in this repo compose the github-heroku-attack-rabbits documentation:
* (**YOU ARE HERE**) The [docs](https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/docs) branch
contains the files needed to generate the
[github-heroku-attack-rabbits documentation site](https://pages.charlesreid1.com/github-heroku-attack-rabbits).
* The [gh-pages](https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/gh-pages) branch
contains the static files generated from the documentation.
The contents of this branch compose the
[github-heroku-attack-rabbits documentation site](https://pages.charlesreid1.com/github-heroku-attack-rabbits).
Two branches illustrate github-heroku-attack-rabbits in practice:
* The [secret](https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/secret) branch contains the files needed to create the secret page.
This repository is public, so obviously these aren't *actually* secret,
but in practice this would be in a protected repository.
* The [heroku-pages](https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/heroku-pages) branch
contains the content that is actually pushed to Heroku - that is,
the final Flask app.
## Contents
An overview of the steps:
[Get Started with Heroku](heroku.md)
[Get Started with Github](github.md)
[Initialize Repository: Branches](repo.md)
[Create a Flask App using Flask-Dance](flask.md)
* [Authenticate users based on Github membership only](flask_auth_github.md)
* [Authenticate users based on organization or team membership](flask_auth_org.md)
* [Authenticate users based on some other criteria](flask_auth_other.md)
* [Protection portions of the site](flask_auth_portions.md)
[Test Flask App Locally](flask_local.md)
[Deploying Flask App to Heroku](flask_heroku.md)
[Custom Domains](custom_domains.md)
## Links
Python software used:
* [Flask](http://flask.pocoo.org/)
* [Flask-dance](https://github.com/singingwolfboy/flask-dance)
* [Flask-dance-github](https://github.com/singingwolfboy/flask-dance-github)
* [mkdocs-material (documentation theme)](https://github.com/squidfunk/mkdocs-material)
* [mkdocs (documentation)](http://www.mkdocs.org/)
Commercial services:
* [Heroku](https://heroku.com)
* [Github](https://github.com)
## License
This is released under the [WTFPL](https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/docs/LICENSE).

110
docs/repo.md

@ -1,110 +0,0 @@ @@ -1,110 +0,0 @@
# Initialize Git Repository
Let's talk through how a repository should be laid out
if we're going to be hosting a Flask app on Heroku.
## Branches
We will need a minimum of two branches. Here we specify
the names that these branches will have in your Github repo,
**which is different from the names of the branches on Heroku**:
Branches on Github:
* `heroku-pages` - this branch contains the content that Heroku will host.
Specifically, it contains the Flask application in a `.py` file,
and a few other files to help Heroku determine how to run the app
and what to install.
* `master` - this branch contains the content used to generate the documentation
and page content that is being hosted behind the Heroku attack sheep.
The documentation you are reading right now is from the master branch,
and was made with `mkdocs`.
On Heroku, we only have a single branch:
* `master` (Heroku) maps to `heroku-pages` (Github)
## Repo Layout
Let's talk about the layout of the repository.
If you wish to build the site in order to deploy it to Heroku,
you should clone the `master` branch (preparing to make the
content for your attack sheep-protected page):
```
$ git clone -b master https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits.git
$ cd github-heroku-attack-rabbits
```
Once you are *inside* the master branch, clone the repo again,
but this time clone the `heroku-pages` branch, and clone it
to the `site/` folder:
```
$ git clone -b heroku-pages https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits.git site
$ cd site
```
Now you will want to set up the Heroku remote:
```
$ heroku git:remote -a my-cool-project
```
The layout should now be:
```
my-cool-project-repo/ <-- my-cool-project repo pointing to master branch
docs/ \
index.md |
heroku.md | <-- mkdocs files
... | (can use any static content generator:
| pelican, sphinx, etc.)
mkdocs.yml /
site/ <-- my-cool-project repo pointing to heroku-pages branch
Procfile \
github.py | <-- heroku python app files
requirements.txt | (can also use ruby, php, js, etc.)
runtime.txt | (can also use ruby, php, js, etc.)
... /
content/ \
index.html | <-- static content hosted by Flask
sitemap.xml |
... /
```
## Workflow
Once you have things set up according to the instructions and diagram above,
you're ready to run the push-to-deploy workflow and start running your secret
site on Heroku.

676
flask/index.html

@ -0,0 +1,676 @@ @@ -0,0 +1,676 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<link rel="canonical" href="https://pages.charlesreid1.com/github-heroku-attack-rabbits/flask/">
<meta name="lang:clipboard.copy" content="Copy to clipboard">
<meta name="lang:clipboard.copied" content="Copied to clipboard">
<meta name="lang:search.language" content="en">
<meta name="lang:search.pipeline.stopwords" content="True">
<meta name="lang:search.pipeline.trimmer" content="True">
<meta name="lang:search.result.none" content="No matching documents">
<meta name="lang:search.result.one" content="1 matching document">
<meta name="lang:search.result.other" content="# matching documents">
<meta name="lang:search.tokenizer" content="[\s\-]+">
<link rel="shortcut icon" href="../">
<meta name="generator" content="mkdocs-0.17.3, mkdocs-material-2.7.2">
<title>Create a Flask App using Flask-Dance - github-heroku-attack-rabbits</title>
<link rel="stylesheet" href="../assets/stylesheets/application.8d40d89b.css">
<link rel="stylesheet" href="../assets/stylesheets/application-palette.6079476c.css">
<script src="../assets/javascripts/modernizr.1aa3b519.js"></script>
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Questrial:300,400,400i,700|Roboto+Mono">
<style>body,input{font-family:"Questrial","Helvetica Neue",Helvetica,Arial,sans-serif}code,kbd,pre{font-family:"Roboto Mono","Courier New",Courier,monospace}</style>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="../css/custom.css">
</head>
<body dir="ltr" data-md-color-primary="red" data-md-color-accent="red">
<svg class="md-svg">
<defs>
<svg xmlns="http://www.w3.org/2000/svg" width="416" height="448"
viewBox="0 0 416 448" id="github">
<path fill="currentColor" d="M160 304q0 10-3.125 20.5t-10.75 19-18.125
8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19 18.125-8.5
18.125 8.5 10.75 19 3.125 20.5zM320 304q0 10-3.125 20.5t-10.75
19-18.125 8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19
18.125-8.5 18.125 8.5 10.75 19 3.125 20.5zM360
304q0-30-17.25-51t-46.75-21q-10.25 0-48.75 5.25-17.75 2.75-39.25
2.75t-39.25-2.75q-38-5.25-48.75-5.25-29.5 0-46.75 21t-17.25 51q0 22 8
38.375t20.25 25.75 30.5 15 35 7.375 37.25 1.75h42q20.5 0
37.25-1.75t35-7.375 30.5-15 20.25-25.75 8-38.375zM416 260q0 51.75-15.25
82.75-9.5 19.25-26.375 33.25t-35.25 21.5-42.5 11.875-42.875 5.5-41.75
1.125q-19.5 0-35.5-0.75t-36.875-3.125-38.125-7.5-34.25-12.875-30.25-20.25-21.5-28.75q-15.5-30.75-15.5-82.75
0-59.25 34-99-6.75-20.5-6.75-42.5 0-29 12.75-54.5 27 0 47.5 9.875t47.25
30.875q36.75-8.75 77.25-8.75 37 0 70 8 26.25-20.5
46.75-30.25t47.25-9.75q12.75 25.5 12.75 54.5 0 21.75-6.75 42 34 40 34
99.5z" />
</svg>
</defs>
</svg>
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="search" autocomplete="off">
<label class="md-overlay" data-md-component="overlay" for="drawer"></label>
<a href="#create-a-flask-app-using-flask-dance" tabindex="1" class="md-skip">
Skip to content
</a>
<header class="md-header" data-md-component="header">
<nav class="md-header-nav md-grid">
<div class="md-flex">
<div class="md-flex__cell md-flex__cell--shrink">
<a href="https://pages.charlesreid1.com/github-heroku-attack-rabbits" title="github-heroku-attack-rabbits" class="md-header-nav__button md-logo">
<img src="../img/bunny.png" width="24" height="24">
</a>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--menu md-header-nav__button" for="drawer"></label>
</div>
<div class="md-flex__cell md-flex__cell--stretch">
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
<span class="md-header-nav__topic">
github-heroku-attack-rabbits
</span>
<span class="md-header-nav__topic">
Create a Flask App using Flask-Dance
</span>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--search md-header-nav__button" for="search"></label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="query" data-md-state="active">
<label class="md-icon md-search__icon" for="search"></label>
<button type="reset" class="md-icon md-search__icon" data-md-component="reset" tabindex="-1">
&#xE5CD;
</button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="result">
<div class="md-search-result__meta">
Type to start searching
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<div class="md-header-nav__source">
<a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
charlesreid1/github-heroku-attack-rabbits
</div>
</a>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container">
<main class="md-main">
<div class="md-main__inner md-grid" data-md-component="container">
<div class="md-sidebar md-sidebar--primary" data-md-component="navigation">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" data-md-level="0">
<label class="md-nav__title md-nav__title--site" for="drawer">
<span class="md-nav__button md-logo">
<img src="../img/bunny.png" width="48" height="48">
</span>
github-heroku-attack-rabbits
</label>
<div class="md-nav__source">
<a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
charlesreid1/github-heroku-attack-rabbits
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href=".." title="Index" class="md-nav__link">
Index
</a>
</li>
<li class="md-nav__item">
<a href="../heroku/" title="Get Started with Heroku" class="md-nav__link">
Get Started with Heroku
</a>
</li>
<li class="md-nav__item">
<a href="../github/" title="Get Started with Github" class="md-nav__link">
Get Started with Github
</a>
</li>
<li class="md-nav__item">
<a href="../repo/" title="Initialize Repository: Branches" class="md-nav__link">
Initialize Repository: Branches
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-toggle md-nav__toggle" data-md-toggle="toc" type="checkbox" id="toc">
<a href="./" title="Create a Flask App using Flask-Dance" class="md-nav__link md-nav__link--active">
Create a Flask App using Flask-Dance
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-6" type="checkbox" id="nav-6">
<label class="md-nav__link" for="nav-6">
Flask
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-6">
Flask
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../flask_auth_github/" title="Authenticate users based on Github membership only" class="md-nav__link">
Authenticate users based on Github membership only
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_org/" title="Authenticate users based on organization or team membership" class="md-nav__link">
Authenticate users based on organization or team membership
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_other/" title="Authenticate users based on some other criteria" class="md-nav__link">
Authenticate users based on some other criteria
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_portions/" title="Protection portions of the site" class="md-nav__link">
Protection portions of the site
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../flask_local/" title="Test Flask App Locally" class="md-nav__link">
Test Flask App Locally
</a>
</li>
<li class="md-nav__item">
<a href="../flask_heroku/" title="Deploying Flask App to Heroku" class="md-nav__link">
Deploying Flask App to Heroku
</a>
</li>
<li class="md-nav__item">
<a href="../custom_domains/" title="Custom Domains" class="md-nav__link">
Custom Domains
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="toc">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary">
</nav>
</div>
</div>
</div>
<div class="md-content">
<article class="md-content__inner md-typeset">
<h1 id="create-a-flask-app-using-flask-dance">Create a Flask App using Flask-Dance</h1>
<p>This is the heart of the method.</p>
<p>The best thing to do here is just to walk you through the script.</p>
<p>Import statements:</p>
<pre><code class="python">import os, json
from os.path import join, isfile, isdir
from werkzeug.contrib.fixers import ProxyFix
from flask import Flask, redirect, url_for, send_from_directory
from flask_dance.contrib.github import make_github_blueprint, github
</code></pre>
<p>Note that flask-dance adds an OAuth login/callback route
to your Flask app by creating a <code>/login</code> blueprint,
meaning all the OAuth stuff is just magically available
via <code>/login</code>.</p>
<p>Set paths for static content:</p>
<pre><code class="python">PROJECT_ROOT = os.path.dirname(os.path.realpath(__file__))
STATIC_PATH = 'content'
</code></pre>
<p>Create and configure app. This requires confidential information
for the Github application you created, specifically the client
ID and client secret. These are at the very top of the page when
you visit your app's settings page.</p>
<p>To find this, after you log in, click your profile photo in the
upper right &gt; Settings &gt; Developer Settings &gt; OAuth Apps &gt; click the
name for your OAuth app.</p>
<pre><code class="python">app = Flask(__name__)
# this worked locally, but not on heroku
app.wsgi_app = ProxyFix(app.wsgi_app)
app.secret_key = os.environ.get(&quot;FLASK_SECRET_KEY&quot;, &quot;9502861d41e8729c5cae3225920b1b46&quot;)
app.config[&quot;RESULT_STATIC_PATH&quot;] = STATIC_PATH #os.path.join(PROJECT_ROOT,STATIC_PATH)
app.config[&quot;GITHUB_OAUTH_CLIENT_ID&quot;] = os.environ.get(&quot;GITHUB_OAUTH_CLIENT_ID&quot;)
app.config[&quot;GITHUB_OAUTH_CLIENT_SECRET&quot;] = os.environ.get(&quot;GITHUB_OAUTH_CLIENT_SECRET&quot;)
</code></pre>
<p>Now the magic happens: we use flask-dance to create a blueprint
that has methods and settings all ready to go for us to do the
OAuth dance.</p>
<p><code>make_github_blueprint()</code> is part of the contrib module of flask-dance.
There are several similar methods to generate blueprints for
authenticating with other APIs.</p>
<pre><code class="python">github_bp = make_github_blueprint(
client_id = os.environ.get('GITHUB_OAUTH_CLIENT_ID'),
client_secret = os.environ.get('GITHUB_OAUTH_CLIENT_SECRET'),
scope='read:org')
app.register_blueprint(github_bp, url_prefix=&quot;/login&quot;)
contents404 = &quot;&lt;html&gt;&lt;body&gt;&lt;h1&gt;Status: Error 404 Page Not Found&lt;/h1&gt;&lt;/body&gt;&lt;/html&gt;&quot;
contents403 = &quot;&lt;html&gt;&lt;body&gt;&lt;h1&gt;Status: Error 403 Access Denied&lt;/h1&gt;&lt;/body&gt;&lt;/html&gt;&quot;
contents200 = &quot;&lt;html&gt;&lt;body&gt;&lt;h1&gt;Status: OK 200&lt;/h1&gt;&lt;/body&gt;&lt;/html&gt;&quot;
</code></pre>
<p>Deal with the <code>/</code> route first:</p>
<ul>
<li>Check if authorized, if not, redirect them to the login URL
(magical URLs taken care of magically by our <code>make_github_blueprint</code>
function above)</li>
<li>If user is authorized (i.e., if they have gone through the OAuth
process and given their passsword to Github and been redirected
to your app with an OAuth token), then the next step is to
find out some information about them.</li>
<li>Use the <code>github</code> object to call the Github API directly.</li>
<li>Decide what to do from there.</li>
</ul>
<pre><code class="python">@app.route('/')
def index():
if not github.authorized:
return redirect(url_for(&quot;github.login&quot;))
resp = github.get(&quot;/user/orgs&quot;)
if resp.ok:
all_orgs = resp.json()
for org in all_orgs:
if org['login']=='rainbow-mind-machine':
</code></pre>
<p>The next line is important to how the server works:
if all of the criteria above have been met, we return
a static file:</p>
<pre><code class="python"> return send_from_directory(STATIC_PATH, 'index.html')
</code></pre>
<p>This is normally "bad practice," and numerous type A people
on the internet will tell you Flask should not be used for
serving static files, and that you should use nginx etc.,
but these fail to igonore the following:</p>
<ul>
<li>Heroku does not let you run or configure nginx</li>
<li>For crying out loud this example is about attack rabbits
stop taking everything so seriously</li>
</ul>
<p>Now that we've got that out of the way...</p>
<p>Here's how we serve up static files. This is a total hack,
but it works. It takes any arbitrary path supplied by the
user, and attempts to find a corresponding file to serve up
on disk. </p>
<p>If the user passes a file, then that file is served up.</p>
<p>If the user passes a directory, then <code>index.html</code> is served up.</p>
<p>If the user asks for a non-existent file, a 404 error is shown.</p>
<p>If the user is not allowed to view the content, they will face
the bowel-emptying terrors of the 403 error.</p>
<pre><code class="python">@app.route('/&lt;path:path&gt;')
def catch_all(path):
if not github.authorized:
return redirect(url_for(&quot;github.login&quot;))
username = github.get(&quot;/user&quot;).json()['login']
rsp = app.config[&quot;RESULT_STATIC_PATH&quot;]
resp = github.get(&quot;/user/orgs&quot;)
if resp.ok:
all_orgs = resp.json()
for org in all_orgs:
if org['login']=='dcppc':
if(path==''):
return send_from_directory(rsp, 'index.html')
elif(isdir(join(rsp,path))):
return send_from_directory(join(rsp,path),'index.html')
elif(isfile(join(rsp,path))):
return send_from_directory(rsp, path)
else:
return contents404
return contents403
</code></pre>
<p>Last, set a default 404 handler, and run the app:</p>
<pre><code class="python">@app.errorhandler(404)
def oops(e):
return contents404
if __name__ == &quot;__main__&quot;:
app.run()
</code></pre>
</article>
</div>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-nav">
<nav class="md-footer-nav__inner md-grid">
<a href="../repo/" title="Initialize Repository: Branches" class="md-flex md-footer-nav__link md-footer-nav__link--prev" rel="prev">
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-back md-footer-nav__button"></i>
</div>
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Previous
</span>
Initialize Repository: Branches
</span>
</div>
</a>
<a href="../flask_auth_github/" title="Authenticate users based on Github membership only" class="md-flex md-footer-nav__link md-footer-nav__link--next" rel="next">
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Next
</span>
Authenticate users based on Github membership only
</span>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>
</div>
</a>
</nav>
</div>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-footer-copyright">
<div class="md-footer-copyright__highlight">
Copyright &copy; 2018 Charles Reid, released under the <a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/docs/LICENSE">WTFPL</a>.<br /><br />Many Bothans died to bring us this documentation.<br /><br />
</div>
powered by
<a href="http://www.mkdocs.org">MkDocs</a>
and
<a href="https://squidfunk.github.io/mkdocs-material/">
Material for MkDocs</a>
</div>
</div>
</div>
</footer>
</div>
<script src="../assets/javascripts/application.0cf9b500.js"></script>
<script>app.initialize({version:"0.17.3",url:{base:".."}})</script>
<script src="../search/require.js"></script>
<script src="../search/search.js"></script>
</body>
</html>

550
flask_auth_github/index.html

@ -0,0 +1,550 @@ @@ -0,0 +1,550 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<link rel="canonical" href="https://pages.charlesreid1.com/github-heroku-attack-rabbits/flask_auth_github/">
<meta name="lang:clipboard.copy" content="Copy to clipboard">
<meta name="lang:clipboard.copied" content="Copied to clipboard">
<meta name="lang:search.language" content="en">
<meta name="lang:search.pipeline.stopwords" content="True">
<meta name="lang:search.pipeline.trimmer" content="True">
<meta name="lang:search.result.none" content="No matching documents">
<meta name="lang:search.result.one" content="1 matching document">
<meta name="lang:search.result.other" content="# matching documents">
<meta name="lang:search.tokenizer" content="[\s\-]+">
<link rel="shortcut icon" href="../">
<meta name="generator" content="mkdocs-0.17.3, mkdocs-material-2.7.2">
<title>Authenticate users based on Github membership only - github-heroku-attack-rabbits</title>
<link rel="stylesheet" href="../assets/stylesheets/application.8d40d89b.css">
<link rel="stylesheet" href="../assets/stylesheets/application-palette.6079476c.css">
<script src="../assets/javascripts/modernizr.1aa3b519.js"></script>
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Questrial:300,400,400i,700|Roboto+Mono">
<style>body,input{font-family:"Questrial","Helvetica Neue",Helvetica,Arial,sans-serif}code,kbd,pre{font-family:"Roboto Mono","Courier New",Courier,monospace}</style>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="../css/custom.css">
</head>
<body dir="ltr" data-md-color-primary="red" data-md-color-accent="red">
<svg class="md-svg">
<defs>
<svg xmlns="http://www.w3.org/2000/svg" width="416" height="448"
viewBox="0 0 416 448" id="github">
<path fill="currentColor" d="M160 304q0 10-3.125 20.5t-10.75 19-18.125
8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19 18.125-8.5
18.125 8.5 10.75 19 3.125 20.5zM320 304q0 10-3.125 20.5t-10.75
19-18.125 8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19
18.125-8.5 18.125 8.5 10.75 19 3.125 20.5zM360
304q0-30-17.25-51t-46.75-21q-10.25 0-48.75 5.25-17.75 2.75-39.25
2.75t-39.25-2.75q-38-5.25-48.75-5.25-29.5 0-46.75 21t-17.25 51q0 22 8
38.375t20.25 25.75 30.5 15 35 7.375 37.25 1.75h42q20.5 0
37.25-1.75t35-7.375 30.5-15 20.25-25.75 8-38.375zM416 260q0 51.75-15.25
82.75-9.5 19.25-26.375 33.25t-35.25 21.5-42.5 11.875-42.875 5.5-41.75
1.125q-19.5 0-35.5-0.75t-36.875-3.125-38.125-7.5-34.25-12.875-30.25-20.25-21.5-28.75q-15.5-30.75-15.5-82.75
0-59.25 34-99-6.75-20.5-6.75-42.5 0-29 12.75-54.5 27 0 47.5 9.875t47.25
30.875q36.75-8.75 77.25-8.75 37 0 70 8 26.25-20.5
46.75-30.25t47.25-9.75q12.75 25.5 12.75 54.5 0 21.75-6.75 42 34 40 34
99.5z" />
</svg>
</defs>
</svg>
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="search" autocomplete="off">
<label class="md-overlay" data-md-component="overlay" for="drawer"></label>
<a href="#authenticate-users-on-github-membership" tabindex="1" class="md-skip">
Skip to content
</a>
<header class="md-header" data-md-component="header">
<nav class="md-header-nav md-grid">
<div class="md-flex">
<div class="md-flex__cell md-flex__cell--shrink">
<a href="https://pages.charlesreid1.com/github-heroku-attack-rabbits" title="github-heroku-attack-rabbits" class="md-header-nav__button md-logo">
<img src="../img/bunny.png" width="24" height="24">
</a>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--menu md-header-nav__button" for="drawer"></label>
</div>
<div class="md-flex__cell md-flex__cell--stretch">
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
<span class="md-header-nav__topic">
github-heroku-attack-rabbits
</span>
<span class="md-header-nav__topic">
Authenticate users based on Github membership only
</span>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--search md-header-nav__button" for="search"></label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="query" data-md-state="active">
<label class="md-icon md-search__icon" for="search"></label>
<button type="reset" class="md-icon md-search__icon" data-md-component="reset" tabindex="-1">
&#xE5CD;
</button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="result">
<div class="md-search-result__meta">
Type to start searching
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<div class="md-header-nav__source">
<a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
charlesreid1/github-heroku-attack-rabbits
</div>
</a>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container">
<main class="md-main">
<div class="md-main__inner md-grid" data-md-component="container">
<div class="md-sidebar md-sidebar--primary" data-md-component="navigation">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" data-md-level="0">
<label class="md-nav__title md-nav__title--site" for="drawer">
<span class="md-nav__button md-logo">
<img src="../img/bunny.png" width="48" height="48">
</span>
github-heroku-attack-rabbits
</label>
<div class="md-nav__source">
<a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
charlesreid1/github-heroku-attack-rabbits
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href=".." title="Index" class="md-nav__link">
Index
</a>
</li>
<li class="md-nav__item">
<a href="../heroku/" title="Get Started with Heroku" class="md-nav__link">
Get Started with Heroku
</a>
</li>
<li class="md-nav__item">
<a href="../github/" title="Get Started with Github" class="md-nav__link">
Get Started with Github
</a>
</li>
<li class="md-nav__item">
<a href="../repo/" title="Initialize Repository: Branches" class="md-nav__link">
Initialize Repository: Branches
</a>
</li>
<li class="md-nav__item">
<a href="../flask/" title="Create a Flask App using Flask-Dance" class="md-nav__link">
Create a Flask App using Flask-Dance
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-6" type="checkbox" id="nav-6" checked>
<label class="md-nav__link" for="nav-6">
Flask
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-6">
Flask
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--active">
<input class="md-toggle md-nav__toggle" data-md-toggle="toc" type="checkbox" id="toc">
<a href="./" title="Authenticate users based on Github membership only" class="md-nav__link md-nav__link--active">
Authenticate users based on Github membership only
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_org/" title="Authenticate users based on organization or team membership" class="md-nav__link">
Authenticate users based on organization or team membership
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_other/" title="Authenticate users based on some other criteria" class="md-nav__link">
Authenticate users based on some other criteria
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_portions/" title="Protection portions of the site" class="md-nav__link">
Protection portions of the site
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../flask_local/" title="Test Flask App Locally" class="md-nav__link">
Test Flask App Locally
</a>
</li>
<li class="md-nav__item">
<a href="../flask_heroku/" title="Deploying Flask App to Heroku" class="md-nav__link">
Deploying Flask App to Heroku
</a>
</li>
<li class="md-nav__item">
<a href="../custom_domains/" title="Custom Domains" class="md-nav__link">
Custom Domains
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="toc">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary">
</nav>
</div>
</div>
</div>
<div class="md-content">
<article class="md-content__inner md-typeset">
<h1 id="authenticate-users-on-github-membership">Authenticate Users on Github Membership</h1>
<p>For the sake of simplicity, will just demonstrate how this
works for a single route, but you can combine different
rules into multiple routes to provide access to different
people on different parts of a site.</p>
<p>Here is the relevant method that serves up <code>index.html</code>
if the user is authenticated:</p>
<pre><code class="python">@app.route('/')
def index():
if not github.authorized:
return redirect(url_for(&quot;github.login&quot;))
resp = github.get(&quot;/user&quot;)
if resp.ok:
return send_from_directory(STATIC_PATH, 'index.html')
return contents403
</code></pre>
</article>
</div>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-nav">
<nav class="md-footer-nav__inner md-grid">
<a href="../flask/" title="Create a Flask App using Flask-Dance" class="md-flex md-footer-nav__link md-footer-nav__link--prev" rel="prev">
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-back md-footer-nav__button"></i>
</div>
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Previous
</span>
Create a Flask App using Flask-Dance
</span>
</div>
</a>
<a href="../flask_auth_org/" title="Authenticate users based on organization or team membership" class="md-flex md-footer-nav__link md-footer-nav__link--next" rel="next">
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Next
</span>
Authenticate users based on organization or team membership
</span>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>
</div>
</a>
</nav>
</div>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-footer-copyright">
<div class="md-footer-copyright__highlight">
Copyright &copy; 2018 Charles Reid, released under the <a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/docs/LICENSE">WTFPL</a>.<br /><br />Many Bothans died to bring us this documentation.<br /><br />
</div>
powered by
<a href="http://www.mkdocs.org">MkDocs</a>
and
<a href="https://squidfunk.github.io/mkdocs-material/">
Material for MkDocs</a>
</div>
</div>
</div>
</footer>
</div>
<script src="../assets/javascripts/application.0cf9b500.js"></script>
<script>app.initialize({version:"0.17.3",url:{base:".."}})</script>
<script src="../search/require.js"></script>
<script src="../search/search.js"></script>
</body>
</html>

549
flask_auth_org/index.html

@ -0,0 +1,549 @@ @@ -0,0 +1,549 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<link rel="canonical" href="https://pages.charlesreid1.com/github-heroku-attack-rabbits/flask_auth_org/">
<meta name="lang:clipboard.copy" content="Copy to clipboard">
<meta name="lang:clipboard.copied" content="Copied to clipboard">
<meta name="lang:search.language" content="en">
<meta name="lang:search.pipeline.stopwords" content="True">
<meta name="lang:search.pipeline.trimmer" content="True">
<meta name="lang:search.result.none" content="No matching documents">
<meta name="lang:search.result.one" content="1 matching document">
<meta name="lang:search.result.other" content="# matching documents">
<meta name="lang:search.tokenizer" content="[\s\-]+">
<link rel="shortcut icon" href="../">
<meta name="generator" content="mkdocs-0.17.3, mkdocs-material-2.7.2">
<title>Authenticate users based on organization or team membership - github-heroku-attack-rabbits</title>
<link rel="stylesheet" href="../assets/stylesheets/application.8d40d89b.css">
<link rel="stylesheet" href="../assets/stylesheets/application-palette.6079476c.css">
<script src="../assets/javascripts/modernizr.1aa3b519.js"></script>
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Questrial:300,400,400i,700|Roboto+Mono">
<style>body,input{font-family:"Questrial","Helvetica Neue",Helvetica,Arial,sans-serif}code,kbd,pre{font-family:"Roboto Mono","Courier New",Courier,monospace}</style>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="../css/custom.css">
</head>
<body dir="ltr" data-md-color-primary="red" data-md-color-accent="red">
<svg class="md-svg">
<defs>
<svg xmlns="http://www.w3.org/2000/svg" width="416" height="448"
viewBox="0 0 416 448" id="github">
<path fill="currentColor" d="M160 304q0 10-3.125 20.5t-10.75 19-18.125
8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19 18.125-8.5
18.125 8.5 10.75 19 3.125 20.5zM320 304q0 10-3.125 20.5t-10.75
19-18.125 8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19
18.125-8.5 18.125 8.5 10.75 19 3.125 20.5zM360
304q0-30-17.25-51t-46.75-21q-10.25 0-48.75 5.25-17.75 2.75-39.25
2.75t-39.25-2.75q-38-5.25-48.75-5.25-29.5 0-46.75 21t-17.25 51q0 22 8
38.375t20.25 25.75 30.5 15 35 7.375 37.25 1.75h42q20.5 0
37.25-1.75t35-7.375 30.5-15 20.25-25.75 8-38.375zM416 260q0 51.75-15.25
82.75-9.5 19.25-26.375 33.25t-35.25 21.5-42.5 11.875-42.875 5.5-41.75
1.125q-19.5 0-35.5-0.75t-36.875-3.125-38.125-7.5-34.25-12.875-30.25-20.25-21.5-28.75q-15.5-30.75-15.5-82.75
0-59.25 34-99-6.75-20.5-6.75-42.5 0-29 12.75-54.5 27 0 47.5 9.875t47.25
30.875q36.75-8.75 77.25-8.75 37 0 70 8 26.25-20.5
46.75-30.25t47.25-9.75q12.75 25.5 12.75 54.5 0 21.75-6.75 42 34 40 34
99.5z" />
</svg>
</defs>
</svg>
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="search" autocomplete="off">
<label class="md-overlay" data-md-component="overlay" for="drawer"></label>
<a href="#authenticate-users-on-organization-or-team-membership" tabindex="1" class="md-skip">
Skip to content
</a>
<header class="md-header" data-md-component="header">
<nav class="md-header-nav md-grid">
<div class="md-flex">
<div class="md-flex__cell md-flex__cell--shrink">
<a href="https://pages.charlesreid1.com/github-heroku-attack-rabbits" title="github-heroku-attack-rabbits" class="md-header-nav__button md-logo">
<img src="../img/bunny.png" width="24" height="24">
</a>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--menu md-header-nav__button" for="drawer"></label>
</div>
<div class="md-flex__cell md-flex__cell--stretch">
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
<span class="md-header-nav__topic">
github-heroku-attack-rabbits
</span>
<span class="md-header-nav__topic">
Authenticate users based on organization or team membership
</span>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--search md-header-nav__button" for="search"></label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="query" data-md-state="active">
<label class="md-icon md-search__icon" for="search"></label>
<button type="reset" class="md-icon md-search__icon" data-md-component="reset" tabindex="-1">
&#xE5CD;
</button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="result">
<div class="md-search-result__meta">
Type to start searching
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<div class="md-header-nav__source">
<a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
charlesreid1/github-heroku-attack-rabbits
</div>
</a>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container">
<main class="md-main">
<div class="md-main__inner md-grid" data-md-component="container">
<div class="md-sidebar md-sidebar--primary" data-md-component="navigation">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" data-md-level="0">
<label class="md-nav__title md-nav__title--site" for="drawer">
<span class="md-nav__button md-logo">
<img src="../img/bunny.png" width="48" height="48">
</span>
github-heroku-attack-rabbits
</label>
<div class="md-nav__source">
<a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
charlesreid1/github-heroku-attack-rabbits
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href=".." title="Index" class="md-nav__link">
Index
</a>
</li>
<li class="md-nav__item">
<a href="../heroku/" title="Get Started with Heroku" class="md-nav__link">
Get Started with Heroku
</a>
</li>
<li class="md-nav__item">
<a href="../github/" title="Get Started with Github" class="md-nav__link">
Get Started with Github
</a>
</li>
<li class="md-nav__item">
<a href="../repo/" title="Initialize Repository: Branches" class="md-nav__link">
Initialize Repository: Branches
</a>
</li>
<li class="md-nav__item">
<a href="../flask/" title="Create a Flask App using Flask-Dance" class="md-nav__link">
Create a Flask App using Flask-Dance
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-6" type="checkbox" id="nav-6" checked>
<label class="md-nav__link" for="nav-6">
Flask
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-6">
Flask
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../flask_auth_github/" title="Authenticate users based on Github membership only" class="md-nav__link">
Authenticate users based on Github membership only
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-toggle md-nav__toggle" data-md-toggle="toc" type="checkbox" id="toc">
<a href="./" title="Authenticate users based on organization or team membership" class="md-nav__link md-nav__link--active">
Authenticate users based on organization or team membership
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_other/" title="Authenticate users based on some other criteria" class="md-nav__link">
Authenticate users based on some other criteria
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_portions/" title="Protection portions of the site" class="md-nav__link">
Protection portions of the site
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../flask_local/" title="Test Flask App Locally" class="md-nav__link">
Test Flask App Locally
</a>
</li>
<li class="md-nav__item">
<a href="../flask_heroku/" title="Deploying Flask App to Heroku" class="md-nav__link">
Deploying Flask App to Heroku
</a>
</li>
<li class="md-nav__item">
<a href="../custom_domains/" title="Custom Domains" class="md-nav__link">
Custom Domains
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="toc">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary">
</nav>
</div>
</div>
</div>
<div class="md-content">
<article class="md-content__inner md-typeset">
<h1 id="authenticate-users-on-organization-or-team-membership">Authenticate Users on Organization or Team Membership</h1>
<p>Here is how we can make access to a given page or route
conditional on membership in an organization (in this
example, membership in the <code>rainbow-mind-machine</code> organization
is required for access):</p>
<pre><code class="python">@app.route('/')
def index():
if not github.authorized:
return redirect(url_for(&quot;github.login&quot;))
resp = github.get(&quot;/user/orgs&quot;)
if resp.ok:
all_orgs = resp.json()
for org in all_orgs:
if org['login']=='rainbow-mind-machine':
return send_from_directory(STATIC_PATH, 'index.html')
</code></pre>
</article>
</div>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-nav">
<nav class="md-footer-nav__inner md-grid">
<a href="../flask_auth_github/" title="Authenticate users based on Github membership only" class="md-flex md-footer-nav__link md-footer-nav__link--prev" rel="prev">
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-back md-footer-nav__button"></i>
</div>
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Previous
</span>
Authenticate users based on Github membership only
</span>
</div>
</a>
<a href="../flask_auth_other/" title="Authenticate users based on some other criteria" class="md-flex md-footer-nav__link md-footer-nav__link--next" rel="next">
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Next
</span>
Authenticate users based on some other criteria
</span>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>
</div>
</a>
</nav>
</div>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-footer-copyright">
<div class="md-footer-copyright__highlight">
Copyright &copy; 2018 Charles Reid, released under the <a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/docs/LICENSE">WTFPL</a>.<br /><br />Many Bothans died to bring us this documentation.<br /><br />
</div>
powered by
<a href="http://www.mkdocs.org">MkDocs</a>
and
<a href="https://squidfunk.github.io/mkdocs-material/">
Material for MkDocs</a>
</div>
</div>
</div>
</footer>
</div>
<script src="../assets/javascripts/application.0cf9b500.js"></script>
<script>app.initialize({version:"0.17.3",url:{base:".."}})</script>
<script src="../search/require.js"></script>
<script src="../search/search.js"></script>
</body>
</html>

551
flask_auth_other/index.html

@ -0,0 +1,551 @@ @@ -0,0 +1,551 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<link rel="canonical" href="https://pages.charlesreid1.com/github-heroku-attack-rabbits/flask_auth_other/">
<meta name="lang:clipboard.copy" content="Copy to clipboard">
<meta name="lang:clipboard.copied" content="Copied to clipboard">
<meta name="lang:search.language" content="en">
<meta name="lang:search.pipeline.stopwords" content="True">
<meta name="lang:search.pipeline.trimmer" content="True">
<meta name="lang:search.result.none" content="No matching documents">
<meta name="lang:search.result.one" content="1 matching document">
<meta name="lang:search.result.other" content="# matching documents">
<meta name="lang:search.tokenizer" content="[\s\-]+">
<link rel="shortcut icon" href="../">
<meta name="generator" content="mkdocs-0.17.3, mkdocs-material-2.7.2">
<title>Authenticate users based on some other criteria - github-heroku-attack-rabbits</title>
<link rel="stylesheet" href="../assets/stylesheets/application.8d40d89b.css">
<link rel="stylesheet" href="../assets/stylesheets/application-palette.6079476c.css">
<script src="../assets/javascripts/modernizr.1aa3b519.js"></script>
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Questrial:300,400,400i,700|Roboto+Mono">
<style>body,input{font-family:"Questrial","Helvetica Neue",Helvetica,Arial,sans-serif}code,kbd,pre{font-family:"Roboto Mono","Courier New",Courier,monospace}</style>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="../css/custom.css">
</head>
<body dir="ltr" data-md-color-primary="red" data-md-color-accent="red">
<svg class="md-svg">
<defs>
<svg xmlns="http://www.w3.org/2000/svg" width="416" height="448"
viewBox="0 0 416 448" id="github">
<path fill="currentColor" d="M160 304q0 10-3.125 20.5t-10.75 19-18.125
8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19 18.125-8.5
18.125 8.5 10.75 19 3.125 20.5zM320 304q0 10-3.125 20.5t-10.75
19-18.125 8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19
18.125-8.5 18.125 8.5 10.75 19 3.125 20.5zM360
304q0-30-17.25-51t-46.75-21q-10.25 0-48.75 5.25-17.75 2.75-39.25
2.75t-39.25-2.75q-38-5.25-48.75-5.25-29.5 0-46.75 21t-17.25 51q0 22 8
38.375t20.25 25.75 30.5 15 35 7.375 37.25 1.75h42q20.5 0
37.25-1.75t35-7.375 30.5-15 20.25-25.75 8-38.375zM416 260q0 51.75-15.25
82.75-9.5 19.25-26.375 33.25t-35.25 21.5-42.5 11.875-42.875 5.5-41.75
1.125q-19.5 0-35.5-0.75t-36.875-3.125-38.125-7.5-34.25-12.875-30.25-20.25-21.5-28.75q-15.5-30.75-15.5-82.75
0-59.25 34-99-6.75-20.5-6.75-42.5 0-29 12.75-54.5 27 0 47.5 9.875t47.25
30.875q36.75-8.75 77.25-8.75 37 0 70 8 26.25-20.5
46.75-30.25t47.25-9.75q12.75 25.5 12.75 54.5 0 21.75-6.75 42 34 40 34
99.5z" />
</svg>
</defs>
</svg>
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="search" autocomplete="off">
<label class="md-overlay" data-md-component="overlay" for="drawer"></label>
<a href="#authenticate-users-on-other-criteria" tabindex="1" class="md-skip">
Skip to content
</a>
<header class="md-header" data-md-component="header">
<nav class="md-header-nav md-grid">
<div class="md-flex">
<div class="md-flex__cell md-flex__cell--shrink">
<a href="https://pages.charlesreid1.com/github-heroku-attack-rabbits" title="github-heroku-attack-rabbits" class="md-header-nav__button md-logo">
<img src="../img/bunny.png" width="24" height="24">
</a>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--menu md-header-nav__button" for="drawer"></label>
</div>
<div class="md-flex__cell md-flex__cell--stretch">
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
<span class="md-header-nav__topic">
github-heroku-attack-rabbits
</span>
<span class="md-header-nav__topic">
Authenticate users based on some other criteria
</span>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--search md-header-nav__button" for="search"></label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="query" data-md-state="active">
<label class="md-icon md-search__icon" for="search"></label>
<button type="reset" class="md-icon md-search__icon" data-md-component="reset" tabindex="-1">
&#xE5CD;
</button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="result">
<div class="md-search-result__meta">
Type to start searching
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<div class="md-header-nav__source">
<a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
charlesreid1/github-heroku-attack-rabbits
</div>
</a>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container">
<main class="md-main">
<div class="md-main__inner md-grid" data-md-component="container">
<div class="md-sidebar md-sidebar--primary" data-md-component="navigation">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" data-md-level="0">
<label class="md-nav__title md-nav__title--site" for="drawer">
<span class="md-nav__button md-logo">
<img src="../img/bunny.png" width="48" height="48">
</span>
github-heroku-attack-rabbits
</label>
<div class="md-nav__source">
<a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
charlesreid1/github-heroku-attack-rabbits
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href=".." title="Index" class="md-nav__link">
Index
</a>
</li>
<li class="md-nav__item">
<a href="../heroku/" title="Get Started with Heroku" class="md-nav__link">
Get Started with Heroku
</a>
</li>
<li class="md-nav__item">
<a href="../github/" title="Get Started with Github" class="md-nav__link">
Get Started with Github
</a>
</li>
<li class="md-nav__item">
<a href="../repo/" title="Initialize Repository: Branches" class="md-nav__link">
Initialize Repository: Branches
</a>
</li>
<li class="md-nav__item">
<a href="../flask/" title="Create a Flask App using Flask-Dance" class="md-nav__link">
Create a Flask App using Flask-Dance
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-6" type="checkbox" id="nav-6" checked>
<label class="md-nav__link" for="nav-6">
Flask
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-6">
Flask
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../flask_auth_github/" title="Authenticate users based on Github membership only" class="md-nav__link">
Authenticate users based on Github membership only
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_org/" title="Authenticate users based on organization or team membership" class="md-nav__link">
Authenticate users based on organization or team membership
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-toggle md-nav__toggle" data-md-toggle="toc" type="checkbox" id="toc">
<a href="./" title="Authenticate users based on some other criteria" class="md-nav__link md-nav__link--active">
Authenticate users based on some other criteria
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_portions/" title="Protection portions of the site" class="md-nav__link">
Protection portions of the site
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../flask_local/" title="Test Flask App Locally" class="md-nav__link">
Test Flask App Locally
</a>
</li>
<li class="md-nav__item">
<a href="../flask_heroku/" title="Deploying Flask App to Heroku" class="md-nav__link">
Deploying Flask App to Heroku
</a>
</li>
<li class="md-nav__item">
<a href="../custom_domains/" title="Custom Domains" class="md-nav__link">
Custom Domains
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="toc">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary">
</nav>
</div>
</div>
</div>
<div class="md-content">
<article class="md-content__inner md-typeset">
<h1 id="authenticate-users-on-other-criteria">Authenticate Users on Other Criteria</h1>
<p>Suppose we wanted to do something silly like restrict
access to a page to users with Github handles that were
between 5 and 7 letters.</p>
<p>Here is the relevant method that serves up <code>index.html</code>
if the user's Github handle is 5-7 letters long:</p>
<pre><code class="python">@app.route('/')
def index():
if not github.authorized:
return redirect(url_for(&quot;github.login&quot;))
resp = github.get(&quot;/user&quot;)
if resp.ok:
username = resp.json()['login']
if len(username)&gt;=5 and len(username)&lt;=7:
return send_from_directory(STATIC_PATH, 'index.html')
return contents403
</code></pre>
</article>
</div>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-nav">
<nav class="md-footer-nav__inner md-grid">
<a href="../flask_auth_org/" title="Authenticate users based on organization or team membership" class="md-flex md-footer-nav__link md-footer-nav__link--prev" rel="prev">
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-back md-footer-nav__button"></i>
</div>
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Previous
</span>
Authenticate users based on organization or team membership
</span>
</div>
</a>
<a href="../flask_auth_portions/" title="Protection portions of the site" class="md-flex md-footer-nav__link md-footer-nav__link--next" rel="next">
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Next
</span>
Protection portions of the site
</span>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>
</div>
</a>
</nav>
</div>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-footer-copyright">
<div class="md-footer-copyright__highlight">
Copyright &copy; 2018 Charles Reid, released under the <a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/docs/LICENSE">WTFPL</a>.<br /><br />Many Bothans died to bring us this documentation.<br /><br />
</div>
powered by
<a href="http://www.mkdocs.org">MkDocs</a>
and
<a href="https://squidfunk.github.io/mkdocs-material/">
Material for MkDocs</a>
</div>
</div>
</div>
</footer>
</div>
<script src="../assets/javascripts/application.0cf9b500.js"></script>
<script>app.initialize({version:"0.17.3",url:{base:".."}})</script>
<script src="../search/require.js"></script>
<script src="../search/search.js"></script>
</body>
</html>

586
flask_auth_portions/index.html

@ -0,0 +1,586 @@ @@ -0,0 +1,586 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<link rel="canonical" href="https://pages.charlesreid1.com/github-heroku-attack-rabbits/flask_auth_portions/">
<meta name="lang:clipboard.copy" content="Copy to clipboard">
<meta name="lang:clipboard.copied" content="Copied to clipboard">
<meta name="lang:search.language" content="en">
<meta name="lang:search.pipeline.stopwords" content="True">
<meta name="lang:search.pipeline.trimmer" content="True">
<meta name="lang:search.result.none" content="No matching documents">
<meta name="lang:search.result.one" content="1 matching document">
<meta name="lang:search.result.other" content="# matching documents">
<meta name="lang:search.tokenizer" content="[\s\-]+">
<link rel="shortcut icon" href="../">
<meta name="generator" content="mkdocs-0.17.3, mkdocs-material-2.7.2">
<title>Protection portions of the site - github-heroku-attack-rabbits</title>
<link rel="stylesheet" href="../assets/stylesheets/application.8d40d89b.css">
<link rel="stylesheet" href="../assets/stylesheets/application-palette.6079476c.css">
<script src="../assets/javascripts/modernizr.1aa3b519.js"></script>
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Questrial:300,400,400i,700|Roboto+Mono">
<style>body,input{font-family:"Questrial","Helvetica Neue",Helvetica,Arial,sans-serif}code,kbd,pre{font-family:"Roboto Mono","Courier New",Courier,monospace}</style>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="../css/custom.css">
</head>
<body dir="ltr" data-md-color-primary="red" data-md-color-accent="red">
<svg class="md-svg">
<defs>
<svg xmlns="http://www.w3.org/2000/svg" width="416" height="448"
viewBox="0 0 416 448" id="github">
<path fill="currentColor" d="M160 304q0 10-3.125 20.5t-10.75 19-18.125
8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19 18.125-8.5
18.125 8.5 10.75 19 3.125 20.5zM320 304q0 10-3.125 20.5t-10.75
19-18.125 8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19
18.125-8.5 18.125 8.5 10.75 19 3.125 20.5zM360
304q0-30-17.25-51t-46.75-21q-10.25 0-48.75 5.25-17.75 2.75-39.25
2.75t-39.25-2.75q-38-5.25-48.75-5.25-29.5 0-46.75 21t-17.25 51q0 22 8
38.375t20.25 25.75 30.5 15 35 7.375 37.25 1.75h42q20.5 0
37.25-1.75t35-7.375 30.5-15 20.25-25.75 8-38.375zM416 260q0 51.75-15.25
82.75-9.5 19.25-26.375 33.25t-35.25 21.5-42.5 11.875-42.875 5.5-41.75
1.125q-19.5 0-35.5-0.75t-36.875-3.125-38.125-7.5-34.25-12.875-30.25-20.25-21.5-28.75q-15.5-30.75-15.5-82.75
0-59.25 34-99-6.75-20.5-6.75-42.5 0-29 12.75-54.5 27 0 47.5 9.875t47.25
30.875q36.75-8.75 77.25-8.75 37 0 70 8 26.25-20.5
46.75-30.25t47.25-9.75q12.75 25.5 12.75 54.5 0 21.75-6.75 42 34 40 34
99.5z" />
</svg>
</defs>
</svg>
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="search" autocomplete="off">
<label class="md-overlay" data-md-component="overlay" for="drawer"></label>
<a href="#authenticate-different-users-on-different-portions-of-site" tabindex="1" class="md-skip">
Skip to content
</a>
<header class="md-header" data-md-component="header">
<nav class="md-header-nav md-grid">
<div class="md-flex">
<div class="md-flex__cell md-flex__cell--shrink">
<a href="https://pages.charlesreid1.com/github-heroku-attack-rabbits" title="github-heroku-attack-rabbits" class="md-header-nav__button md-logo">
<img src="../img/bunny.png" width="24" height="24">
</a>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--menu md-header-nav__button" for="drawer"></label>
</div>
<div class="md-flex__cell md-flex__cell--stretch">
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
<span class="md-header-nav__topic">
github-heroku-attack-rabbits
</span>
<span class="md-header-nav__topic">
Protection portions of the site
</span>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--search md-header-nav__button" for="search"></label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="query" data-md-state="active">
<label class="md-icon md-search__icon" for="search"></label>
<button type="reset" class="md-icon md-search__icon" data-md-component="reset" tabindex="-1">
&#xE5CD;
</button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="result">
<div class="md-search-result__meta">
Type to start searching
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<div class="md-header-nav__source">
<a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
charlesreid1/github-heroku-attack-rabbits
</div>
</a>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container">
<main class="md-main">
<div class="md-main__inner md-grid" data-md-component="container">
<div class="md-sidebar md-sidebar--primary" data-md-component="navigation">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" data-md-level="0">
<label class="md-nav__title md-nav__title--site" for="drawer">
<span class="md-nav__button md-logo">
<img src="../img/bunny.png" width="48" height="48">
</span>
github-heroku-attack-rabbits
</label>
<div class="md-nav__source">
<a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
charlesreid1/github-heroku-attack-rabbits
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href=".." title="Index" class="md-nav__link">
Index
</a>
</li>
<li class="md-nav__item">
<a href="../heroku/" title="Get Started with Heroku" class="md-nav__link">
Get Started with Heroku
</a>
</li>
<li class="md-nav__item">
<a href="../github/" title="Get Started with Github" class="md-nav__link">
Get Started with Github
</a>
</li>
<li class="md-nav__item">
<a href="../repo/" title="Initialize Repository: Branches" class="md-nav__link">
Initialize Repository: Branches
</a>
</li>
<li class="md-nav__item">
<a href="../flask/" title="Create a Flask App using Flask-Dance" class="md-nav__link">
Create a Flask App using Flask-Dance
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-6" type="checkbox" id="nav-6" checked>
<label class="md-nav__link" for="nav-6">
Flask
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-6">
Flask
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../flask_auth_github/" title="Authenticate users based on Github membership only" class="md-nav__link">
Authenticate users based on Github membership only
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_org/" title="Authenticate users based on organization or team membership" class="md-nav__link">
Authenticate users based on organization or team membership
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_other/" title="Authenticate users based on some other criteria" class="md-nav__link">
Authenticate users based on some other criteria
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-toggle md-nav__toggle" data-md-toggle="toc" type="checkbox" id="toc">
<a href="./" title="Protection portions of the site" class="md-nav__link md-nav__link--active">
Protection portions of the site
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../flask_local/" title="Test Flask App Locally" class="md-nav__link">
Test Flask App Locally
</a>
</li>
<li class="md-nav__item">
<a href="../flask_heroku/" title="Deploying Flask App to Heroku" class="md-nav__link">
Deploying Flask App to Heroku
</a>
</li>
<li class="md-nav__item">
<a href="../custom_domains/" title="Custom Domains" class="md-nav__link">
Custom Domains
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="toc">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary">
</nav>
</div>
</div>
</div>
<div class="md-content">
<article class="md-content__inner md-typeset">
<h1 id="authenticate-different-users-on-different-portions-of-site">Authenticate Different Users on Different Portions of Site</h1>
<p><strong>NOTE: if you are authenticating using membership on a team, you will need the
team id of the team you are interested in authenticating against.</strong></p>
<p>For this example, let's expand the routes we're looking at
a bit more.</p>
<p>Suppose we have two folders, <code>team_only</code> and <code>org_only</code>.</p>
<p>The <code>team_only</code> folder should only be accessible to your team, <code>Team Gold</code>.</p>
<p>The <code>org_only</code> folder should only be accessible to your organization, <code>Colorful Colors</code>.</p>
<p>The main site (i.e., all other files) should be publicly accessible.</p>
<pre><code class="python">@app.route('/')
def index():
return send_from_directory(STATIC_PATH, 'index.html')
@app.route('/team_only/&lt;path:path&gt;')
def team_gold(path):
if not github.authorized:
return redirect(url_for(&quot;github.login&quot;))
rsp = app.config[&quot;RESULT_STATIC_PATH&quot;]
resp = github.get(&quot;/user&quot;)
if resp.ok:
username = resp.json()['login']
team_id = 'XXXXX'
resp = github.get(&quot;/teams/%s/members/%s&quot;%( team_id, username ))
if resp.code==204:
team_gold_dir = os.path.join(STATIC_PATH, 'team_only')
return send_from_directory(team_gold_dir, 'index.html')
return contents403
@app.route('/org_only/&lt;path:path&gt;')
def team_gold(path):
if not github.authorized:
return redirect(url_for(&quot;github.login&quot;))
rsp = app.config[&quot;RESULT_STATIC_PATH&quot;]
resp = github.get(&quot;/user&quot;)
if resp.ok:
my_org = 'XXXXXXXX'
all_orgs = resp.json()
for org in all_orgs:
if org['login']==my_org:
color_org_dir = os.path.join(STATIC_PATH, 'org_only')
return send_from_directory(color_org_dir, 'index.html')
return contents403
</code></pre>
</article>
</div>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-nav">
<nav class="md-footer-nav__inner md-grid">
<a href="../flask_auth_other/" title="Authenticate users based on some other criteria" class="md-flex md-footer-nav__link md-footer-nav__link--prev" rel="prev">
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-back md-footer-nav__button"></i>
</div>
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Previous
</span>
Authenticate users based on some other criteria
</span>
</div>
</a>
<a href="../flask_local/" title="Test Flask App Locally" class="md-flex md-footer-nav__link md-footer-nav__link--next" rel="next">
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Next
</span>
Test Flask App Locally
</span>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>
</div>
</a>
</nav>
</div>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-footer-copyright">
<div class="md-footer-copyright__highlight">
Copyright &copy; 2018 Charles Reid, released under the <a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/docs/LICENSE">WTFPL</a>.<br /><br />Many Bothans died to bring us this documentation.<br /><br />
</div>
powered by
<a href="http://www.mkdocs.org">MkDocs</a>
and
<a href="https://squidfunk.github.io/mkdocs-material/">
Material for MkDocs</a>
</div>
</div>
</div>
</footer>
</div>
<script src="../assets/javascripts/application.0cf9b500.js"></script>
<script>app.initialize({version:"0.17.3",url:{base:".."}})</script>
<script src="../search/require.js"></script>
<script src="../search/search.js"></script>
</body>
</html>

708
flask_heroku/index.html

@ -0,0 +1,708 @@ @@ -0,0 +1,708 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<link rel="canonical" href="https://pages.charlesreid1.com/github-heroku-attack-rabbits/flask_heroku/">
<meta name="lang:clipboard.copy" content="Copy to clipboard">
<meta name="lang:clipboard.copied" content="Copied to clipboard">
<meta name="lang:search.language" content="en">
<meta name="lang:search.pipeline.stopwords" content="True">
<meta name="lang:search.pipeline.trimmer" content="True">
<meta name="lang:search.result.none" content="No matching documents">
<meta name="lang:search.result.one" content="1 matching document">
<meta name="lang:search.result.other" content="# matching documents">
<meta name="lang:search.tokenizer" content="[\s\-]+">
<link rel="shortcut icon" href="../">
<meta name="generator" content="mkdocs-0.17.3, mkdocs-material-2.7.2">
<title>Deploying Flask App to Heroku - github-heroku-attack-rabbits</title>
<link rel="stylesheet" href="../assets/stylesheets/application.8d40d89b.css">
<link rel="stylesheet" href="../assets/stylesheets/application-palette.6079476c.css">
<script src="../assets/javascripts/modernizr.1aa3b519.js"></script>
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Questrial:300,400,400i,700|Roboto+Mono">
<style>body,input{font-family:"Questrial","Helvetica Neue",Helvetica,Arial,sans-serif}code,kbd,pre{font-family:"Roboto Mono","Courier New",Courier,monospace}</style>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="../css/custom.css">
</head>
<body dir="ltr" data-md-color-primary="red" data-md-color-accent="red">
<svg class="md-svg">
<defs>
<svg xmlns="http://www.w3.org/2000/svg" width="416" height="448"
viewBox="0 0 416 448" id="github">
<path fill="currentColor" d="M160 304q0 10-3.125 20.5t-10.75 19-18.125
8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19 18.125-8.5
18.125 8.5 10.75 19 3.125 20.5zM320 304q0 10-3.125 20.5t-10.75
19-18.125 8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19
18.125-8.5 18.125 8.5 10.75 19 3.125 20.5zM360
304q0-30-17.25-51t-46.75-21q-10.25 0-48.75 5.25-17.75 2.75-39.25
2.75t-39.25-2.75q-38-5.25-48.75-5.25-29.5 0-46.75 21t-17.25 51q0 22 8
38.375t20.25 25.75 30.5 15 35 7.375 37.25 1.75h42q20.5 0
37.25-1.75t35-7.375 30.5-15 20.25-25.75 8-38.375zM416 260q0 51.75-15.25
82.75-9.5 19.25-26.375 33.25t-35.25 21.5-42.5 11.875-42.875 5.5-41.75
1.125q-19.5 0-35.5-0.75t-36.875-3.125-38.125-7.5-34.25-12.875-30.25-20.25-21.5-28.75q-15.5-30.75-15.5-82.75
0-59.25 34-99-6.75-20.5-6.75-42.5 0-29 12.75-54.5 27 0 47.5 9.875t47.25
30.875q36.75-8.75 77.25-8.75 37 0 70 8 26.25-20.5
46.75-30.25t47.25-9.75q12.75 25.5 12.75 54.5 0 21.75-6.75 42 34 40 34
99.5z" />
</svg>
</defs>
</svg>
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="search" autocomplete="off">
<label class="md-overlay" data-md-component="overlay" for="drawer"></label>
<a href="#deploying-to-heroku" tabindex="1" class="md-skip">
Skip to content
</a>
<header class="md-header" data-md-component="header">
<nav class="md-header-nav md-grid">
<div class="md-flex">
<div class="md-flex__cell md-flex__cell--shrink">
<a href="https://pages.charlesreid1.com/github-heroku-attack-rabbits" title="github-heroku-attack-rabbits" class="md-header-nav__button md-logo">
<img src="../img/bunny.png" width="24" height="24">
</a>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--menu md-header-nav__button" for="drawer"></label>
</div>
<div class="md-flex__cell md-flex__cell--stretch">
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
<span class="md-header-nav__topic">
github-heroku-attack-rabbits
</span>
<span class="md-header-nav__topic">
Deploying Flask App to Heroku
</span>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--search md-header-nav__button" for="search"></label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="query" data-md-state="active">
<label class="md-icon md-search__icon" for="search"></label>
<button type="reset" class="md-icon md-search__icon" data-md-component="reset" tabindex="-1">
&#xE5CD;
</button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="result">
<div class="md-search-result__meta">
Type to start searching
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<div class="md-header-nav__source">
<a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
charlesreid1/github-heroku-attack-rabbits
</div>
</a>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container">
<main class="md-main">
<div class="md-main__inner md-grid" data-md-component="container">
<div class="md-sidebar md-sidebar--primary" data-md-component="navigation">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" data-md-level="0">
<label class="md-nav__title md-nav__title--site" for="drawer">
<span class="md-nav__button md-logo">
<img src="../img/bunny.png" width="48" height="48">
</span>
github-heroku-attack-rabbits
</label>
<div class="md-nav__source">
<a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
charlesreid1/github-heroku-attack-rabbits
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href=".." title="Index" class="md-nav__link">
Index
</a>
</li>
<li class="md-nav__item">
<a href="../heroku/" title="Get Started with Heroku" class="md-nav__link">
Get Started with Heroku
</a>
</li>
<li class="md-nav__item">
<a href="../github/" title="Get Started with Github" class="md-nav__link">
Get Started with Github
</a>
</li>
<li class="md-nav__item">
<a href="../repo/" title="Initialize Repository: Branches" class="md-nav__link">
Initialize Repository: Branches
</a>
</li>
<li class="md-nav__item">
<a href="../flask/" title="Create a Flask App using Flask-Dance" class="md-nav__link">
Create a Flask App using Flask-Dance
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-6" type="checkbox" id="nav-6">
<label class="md-nav__link" for="nav-6">
Flask
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-6">
Flask
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../flask_auth_github/" title="Authenticate users based on Github membership only" class="md-nav__link">
Authenticate users based on Github membership only
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_org/" title="Authenticate users based on organization or team membership" class="md-nav__link">
Authenticate users based on organization or team membership
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_other/" title="Authenticate users based on some other criteria" class="md-nav__link">
Authenticate users based on some other criteria
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_portions/" title="Protection portions of the site" class="md-nav__link">
Protection portions of the site
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../flask_local/" title="Test Flask App Locally" class="md-nav__link">
Test Flask App Locally
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-toggle md-nav__toggle" data-md-toggle="toc" type="checkbox" id="toc">
<label class="md-nav__link md-nav__link--active" for="toc">
Deploying Flask App to Heroku
</label>
<a href="./" title="Deploying Flask App to Heroku" class="md-nav__link md-nav__link--active">
Deploying Flask App to Heroku
</a>
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#repository-setup" title="Repository Setup" class="md-nav__link">
Repository Setup
</a>
</li>
<li class="md-nav__item">
<a href="#heroku-deploy-process" title="Heroku Deploy Process" class="md-nav__link">
Heroku Deploy Process
</a>
</li>
<li class="md-nav__item">
<a href="#heroku-login" title="Heroku Login" class="md-nav__link">
Heroku Login
</a>
</li>
<li class="md-nav__item">
<a href="#add-heroku-remote-to-heroku-pages-branch" title="Add Heroku Remote to heroku-pages Branch" class="md-nav__link">
Add Heroku Remote to heroku-pages Branch
</a>
</li>
<li class="md-nav__item">
<a href="#deploy-to-heroku" title="Deploy to Heroku" class="md-nav__link">
Deploy to Heroku
</a>
</li>
<li class="md-nav__item">
<a href="#check-your-heroku-app" title="Check Your Heroku App" class="md-nav__link">
Check Your Heroku App
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../custom_domains/" title="Custom Domains" class="md-nav__link">
Custom Domains
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="toc">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#repository-setup" title="Repository Setup" class="md-nav__link">
Repository Setup
</a>
</li>
<li class="md-nav__item">
<a href="#heroku-deploy-process" title="Heroku Deploy Process" class="md-nav__link">
Heroku Deploy Process
</a>
</li>
<li class="md-nav__item">
<a href="#heroku-login" title="Heroku Login" class="md-nav__link">
Heroku Login
</a>
</li>
<li class="md-nav__item">
<a href="#add-heroku-remote-to-heroku-pages-branch" title="Add Heroku Remote to heroku-pages Branch" class="md-nav__link">
Add Heroku Remote to heroku-pages Branch
</a>
</li>
<li class="md-nav__item">
<a href="#deploy-to-heroku" title="Deploy to Heroku" class="md-nav__link">
Deploy to Heroku
</a>
</li>
<li class="md-nav__item">
<a href="#check-your-heroku-app" title="Check Your Heroku App" class="md-nav__link">
Check Your Heroku App
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content">
<article class="md-content__inner md-typeset">
<h1 id="deploying-to-heroku">Deploying to Heroku</h1>
<p>Once we have debugged the Flask app and we are happy with it,
we are ready to deploy it to Heroku. </p>
<h2 id="repository-setup">Repository Setup</h2>
<p>To do this, you should set up your repo as follows:</p>
<p>Clone the repo:</p>
<pre><code class="plain">$ git clone https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits.git
</code></pre>
<p>The repo has the following structure:</p>
<pre><code class="plain">github-heroku-attack-rabbits/
LICENSE
README.md
mkdocs.yml
docs/
index.md
...
mkdocs-material/
...
</code></pre>
<p>Now, inside the repo, clone the repo again,
but this time clone the <code>heroku-pages</code> branch
to the <code>site/</code> directory:</p>
<pre><code class="plain">$ cd github-heroku-attack-rabbits/
$ git clone -b heroku-pages https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits.git site
</code></pre>
<h2 id="heroku-deploy-process">Heroku Deploy Process</h2>
<p>To deploy content to Heroku, we add our Heroku project as a git remote
(see the <a href="../heroku/">heroku</a> page for how to do that) and then push to
to the master branch of the heroku remote git repo. Changes are pulled
in by Heroku and the app is restarted each time you run <code>git push</code>.</p>
<p>We walk through the steps below.</p>
<h2 id="heroku-login">Heroku Login</h2>
<p>From the <code>site/</code> directory containing the contents of the <code>heroku-pages</code> branch,
that is, containing the Python flask app, log in to Heroku:</p>
<pre><code class="plain">$ heroku login
</code></pre>
<h2 id="add-heroku-remote-to-heroku-pages-branch">Add Heroku Remote to <code>heroku-pages</code> Branch</h2>
<p>Now have Heroku add the proper git remote address:</p>
<pre><code class="plain">$ heroku git:remote -a &lt;heroku-app-name&gt;
</code></pre>
<p>Now you're ready to deploy to Heroku. </p>
<h2 id="deploy-to-heroku">Deploy to Heroku</h2>
<p>Double check your app is ready, then deploy:</p>
<pre><code class="plain">$ git push heroku heroku-pages:master
</code></pre>
<p>This will push the local branch <code>heroku-pages</code> to
the remote branch <code>master</code> on the <code>heroku</code> remote.
This should begin a pre-commit hook where Heroku
compiles your Python app. You should get the green
light, if you tested your app locally and everything
was good to go.</p>
<h2 id="check-your-heroku-app">Check Your Heroku App</h2>
<p>Your Heroku app will be available at </p>
<pre><code>https://&lt;heroku-app-name&gt;.herokuapp.com
</code></pre>
<p>You should see your Python flask app
show up shortly.</p>
</article>
</div>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-nav">
<nav class="md-footer-nav__inner md-grid">
<a href="../flask_local/" title="Test Flask App Locally" class="md-flex md-footer-nav__link md-footer-nav__link--prev" rel="prev">
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-back md-footer-nav__button"></i>
</div>
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Previous
</span>
Test Flask App Locally
</span>
</div>
</a>
<a href="../custom_domains/" title="Custom Domains" class="md-flex md-footer-nav__link md-footer-nav__link--next" rel="next">
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Next
</span>
Custom Domains
</span>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>
</div>
</a>
</nav>
</div>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-footer-copyright">
<div class="md-footer-copyright__highlight">
Copyright &copy; 2018 Charles Reid, released under the <a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/docs/LICENSE">WTFPL</a>.<br /><br />Many Bothans died to bring us this documentation.<br /><br />
</div>
powered by
<a href="http://www.mkdocs.org">MkDocs</a>
and
<a href="https://squidfunk.github.io/mkdocs-material/">
Material for MkDocs</a>
</div>
</div>
</div>
</footer>
</div>
<script src="../assets/javascripts/application.0cf9b500.js"></script>
<script>app.initialize({version:"0.17.3",url:{base:".."}})</script>
<script src="../search/require.js"></script>
<script src="../search/search.js"></script>
</body>
</html>

605
flask_local/index.html

@ -0,0 +1,605 @@ @@ -0,0 +1,605 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<link rel="canonical" href="https://pages.charlesreid1.com/github-heroku-attack-rabbits/flask_local/">
<meta name="lang:clipboard.copy" content="Copy to clipboard">
<meta name="lang:clipboard.copied" content="Copied to clipboard">
<meta name="lang:search.language" content="en">
<meta name="lang:search.pipeline.stopwords" content="True">
<meta name="lang:search.pipeline.trimmer" content="True">
<meta name="lang:search.result.none" content="No matching documents">
<meta name="lang:search.result.one" content="1 matching document">
<meta name="lang:search.result.other" content="# matching documents">
<meta name="lang:search.tokenizer" content="[\s\-]+">
<link rel="shortcut icon" href="../">
<meta name="generator" content="mkdocs-0.17.3, mkdocs-material-2.7.2">
<title>Test Flask App Locally - github-heroku-attack-rabbits</title>
<link rel="stylesheet" href="../assets/stylesheets/application.8d40d89b.css">
<link rel="stylesheet" href="../assets/stylesheets/application-palette.6079476c.css">
<script src="../assets/javascripts/modernizr.1aa3b519.js"></script>
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Questrial:300,400,400i,700|Roboto+Mono">
<style>body,input{font-family:"Questrial","Helvetica Neue",Helvetica,Arial,sans-serif}code,kbd,pre{font-family:"Roboto Mono","Courier New",Courier,monospace}</style>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="../css/custom.css">
</head>
<body dir="ltr" data-md-color-primary="red" data-md-color-accent="red">
<svg class="md-svg">
<defs>
<svg xmlns="http://www.w3.org/2000/svg" width="416" height="448"
viewBox="0 0 416 448" id="github">
<path fill="currentColor" d="M160 304q0 10-3.125 20.5t-10.75 19-18.125
8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19 18.125-8.5
18.125 8.5 10.75 19 3.125 20.5zM320 304q0 10-3.125 20.5t-10.75
19-18.125 8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19
18.125-8.5 18.125 8.5 10.75 19 3.125 20.5zM360
304q0-30-17.25-51t-46.75-21q-10.25 0-48.75 5.25-17.75 2.75-39.25
2.75t-39.25-2.75q-38-5.25-48.75-5.25-29.5 0-46.75 21t-17.25 51q0 22 8
38.375t20.25 25.75 30.5 15 35 7.375 37.25 1.75h42q20.5 0
37.25-1.75t35-7.375 30.5-15 20.25-25.75 8-38.375zM416 260q0 51.75-15.25
82.75-9.5 19.25-26.375 33.25t-35.25 21.5-42.5 11.875-42.875 5.5-41.75
1.125q-19.5 0-35.5-0.75t-36.875-3.125-38.125-7.5-34.25-12.875-30.25-20.25-21.5-28.75q-15.5-30.75-15.5-82.75
0-59.25 34-99-6.75-20.5-6.75-42.5 0-29 12.75-54.5 27 0 47.5 9.875t47.25
30.875q36.75-8.75 77.25-8.75 37 0 70 8 26.25-20.5
46.75-30.25t47.25-9.75q12.75 25.5 12.75 54.5 0 21.75-6.75 42 34 40 34
99.5z" />
</svg>
</defs>
</svg>
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="search" autocomplete="off">
<label class="md-overlay" data-md-component="overlay" for="drawer"></label>
<a href="#testing-flask-app-locally" tabindex="1" class="md-skip">
Skip to content
</a>
<header class="md-header" data-md-component="header">
<nav class="md-header-nav md-grid">
<div class="md-flex">
<div class="md-flex__cell md-flex__cell--shrink">
<a href="https://pages.charlesreid1.com/github-heroku-attack-rabbits" title="github-heroku-attack-rabbits" class="md-header-nav__button md-logo">
<img src="../img/bunny.png" width="24" height="24">
</a>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--menu md-header-nav__button" for="drawer"></label>
</div>
<div class="md-flex__cell md-flex__cell--stretch">
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
<span class="md-header-nav__topic">
github-heroku-attack-rabbits
</span>
<span class="md-header-nav__topic">
Test Flask App Locally
</span>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--search md-header-nav__button" for="search"></label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="query" data-md-state="active">
<label class="md-icon md-search__icon" for="search"></label>
<button type="reset" class="md-icon md-search__icon" data-md-component="reset" tabindex="-1">
&#xE5CD;
</button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="result">
<div class="md-search-result__meta">
Type to start searching
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<div class="md-header-nav__source">
<a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
charlesreid1/github-heroku-attack-rabbits
</div>
</a>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container">
<main class="md-main">
<div class="md-main__inner md-grid" data-md-component="container">
<div class="md-sidebar md-sidebar--primary" data-md-component="navigation">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" data-md-level="0">
<label class="md-nav__title md-nav__title--site" for="drawer">
<span class="md-nav__button md-logo">
<img src="../img/bunny.png" width="48" height="48">
</span>
github-heroku-attack-rabbits
</label>
<div class="md-nav__source">
<a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
charlesreid1/github-heroku-attack-rabbits
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href=".." title="Index" class="md-nav__link">
Index
</a>
</li>
<li class="md-nav__item">
<a href="../heroku/" title="Get Started with Heroku" class="md-nav__link">
Get Started with Heroku
</a>
</li>
<li class="md-nav__item">
<a href="../github/" title="Get Started with Github" class="md-nav__link">
Get Started with Github
</a>
</li>
<li class="md-nav__item">
<a href="../repo/" title="Initialize Repository: Branches" class="md-nav__link">
Initialize Repository: Branches
</a>
</li>
<li class="md-nav__item">
<a href="../flask/" title="Create a Flask App using Flask-Dance" class="md-nav__link">
Create a Flask App using Flask-Dance
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-6" type="checkbox" id="nav-6">
<label class="md-nav__link" for="nav-6">
Flask
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-6">
Flask
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../flask_auth_github/" title="Authenticate users based on Github membership only" class="md-nav__link">
Authenticate users based on Github membership only
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_org/" title="Authenticate users based on organization or team membership" class="md-nav__link">
Authenticate users based on organization or team membership
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_other/" title="Authenticate users based on some other criteria" class="md-nav__link">
Authenticate users based on some other criteria
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_portions/" title="Protection portions of the site" class="md-nav__link">
Protection portions of the site
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-toggle md-nav__toggle" data-md-toggle="toc" type="checkbox" id="toc">
<label class="md-nav__link md-nav__link--active" for="toc">
Test Flask App Locally
</label>
<a href="./" title="Test Flask App Locally" class="md-nav__link md-nav__link--active">
Test Flask App Locally
</a>
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#next-step" title="Next Step?" class="md-nav__link">
Next Step?
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../flask_heroku/" title="Deploying Flask App to Heroku" class="md-nav__link">
Deploying Flask App to Heroku
</a>
</li>
<li class="md-nav__item">
<a href="../custom_domains/" title="Custom Domains" class="md-nav__link">
Custom Domains
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="toc">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#next-step" title="Next Step?" class="md-nav__link">
Next Step?
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content">
<article class="md-content__inner md-typeset">
<h1 id="testing-flask-app-locally">Testing Flask App Locally</h1>
<p>We set up the Github App to use a callback of <code>https://localhost:5000/login/github/authorized</code>
so that we could test the app locally. Now it is time to test the app locally.</p>
<p>The application needs access to your Github app id and token. Those are provided
via the <code>GITHUB_OAUTH_CLIENT_{ID,SECRET}</code> environment variables. Set these
when you run the actual python command to run the server:</p>
<pre><code class="plain">$ GITHUB_OAUTH_CLIENT_ID=&quot;xxxxxxx&quot; \
GITHUB_OAUTH_CLIENT_SECRET=&quot;xxxxxxx&quot; \
OAUTHLIB_INSECURE_TRANSPORT=true \
python github.py
</code></pre>
<p>This runs the Flask server on port 5000, where it will wait for a visitor.
The way we have our application written in this example, the main <code>/</code> route
will redirect the user to a Github login screen immediately, but you could
also present the user with a friendly welcome page when they go to <code>/</code>,
and only redirect them to the Github login prompt when they visit a
URL like <code>/login</code> or <code>/auth</code>.</p>
<p>Once you run the above command, open the following URL in your browser:</p>
<pre><code class="plain">http://localhost:5000/
</code></pre>
<p><strong>NOTE: Make sure you are logged out of Github and that you clear your cookies
if you are already logged in as one user and wish to authenticate as another.
The login is <em>very</em> persistent so you may need to close and re-open your browser.</strong></p>
<p>Visiting the address above will result in your being redirected to a Github
login page. Once you login, Github will redirect the user back to the
github-heroku-attack-rabbits application with a token that the application
can use to perform actions on behalf of the user.</p>
<h2 id="next-step">Next Step?</h2>
<p>If the app works, the next step is to deploy to Heroku.</p>
</article>
</div>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-nav">
<nav class="md-footer-nav__inner md-grid">
<a href="../flask_auth_portions/" title="Protection portions of the site" class="md-flex md-footer-nav__link md-footer-nav__link--prev" rel="prev">
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-back md-footer-nav__button"></i>
</div>
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Previous
</span>
Protection portions of the site
</span>
</div>
</a>
<a href="../flask_heroku/" title="Deploying Flask App to Heroku" class="md-flex md-footer-nav__link md-footer-nav__link--next" rel="next">
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Next
</span>
Deploying Flask App to Heroku
</span>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>
</div>
</a>
</nav>
</div>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-footer-copyright">
<div class="md-footer-copyright__highlight">
Copyright &copy; 2018 Charles Reid, released under the <a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/docs/LICENSE">WTFPL</a>.<br /><br />Many Bothans died to bring us this documentation.<br /><br />
</div>
powered by
<a href="http://www.mkdocs.org">MkDocs</a>
and
<a href="https://squidfunk.github.io/mkdocs-material/">
Material for MkDocs</a>
</div>
</div>
</div>
</footer>
</div>
<script src="../assets/javascripts/application.0cf9b500.js"></script>
<script>app.initialize({version:"0.17.3",url:{base:".."}})</script>
<script src="../search/require.js"></script>
<script src="../search/search.js"></script>
</body>
</html>

656
github/index.html

@ -0,0 +1,656 @@ @@ -0,0 +1,656 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<link rel="canonical" href="https://pages.charlesreid1.com/github-heroku-attack-rabbits/github/">
<meta name="lang:clipboard.copy" content="Copy to clipboard">
<meta name="lang:clipboard.copied" content="Copied to clipboard">
<meta name="lang:search.language" content="en">
<meta name="lang:search.pipeline.stopwords" content="True">
<meta name="lang:search.pipeline.trimmer" content="True">
<meta name="lang:search.result.none" content="No matching documents">
<meta name="lang:search.result.one" content="1 matching document">
<meta name="lang:search.result.other" content="# matching documents">
<meta name="lang:search.tokenizer" content="[\s\-]+">
<link rel="shortcut icon" href="../">
<meta name="generator" content="mkdocs-0.17.3, mkdocs-material-2.7.2">
<title>Get Started with Github - github-heroku-attack-rabbits</title>
<link rel="stylesheet" href="../assets/stylesheets/application.8d40d89b.css">
<link rel="stylesheet" href="../assets/stylesheets/application-palette.6079476c.css">
<script src="../assets/javascripts/modernizr.1aa3b519.js"></script>
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Questrial:300,400,400i,700|Roboto+Mono">
<style>body,input{font-family:"Questrial","Helvetica Neue",Helvetica,Arial,sans-serif}code,kbd,pre{font-family:"Roboto Mono","Courier New",Courier,monospace}</style>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="../css/custom.css">
</head>
<body dir="ltr" data-md-color-primary="red" data-md-color-accent="red">
<svg class="md-svg">
<defs>
<svg xmlns="http://www.w3.org/2000/svg" width="416" height="448"
viewBox="0 0 416 448" id="github">
<path fill="currentColor" d="M160 304q0 10-3.125 20.5t-10.75 19-18.125
8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19 18.125-8.5
18.125 8.5 10.75 19 3.125 20.5zM320 304q0 10-3.125 20.5t-10.75
19-18.125 8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19
18.125-8.5 18.125 8.5 10.75 19 3.125 20.5zM360
304q0-30-17.25-51t-46.75-21q-10.25 0-48.75 5.25-17.75 2.75-39.25
2.75t-39.25-2.75q-38-5.25-48.75-5.25-29.5 0-46.75 21t-17.25 51q0 22 8
38.375t20.25 25.75 30.5 15 35 7.375 37.25 1.75h42q20.5 0
37.25-1.75t35-7.375 30.5-15 20.25-25.75 8-38.375zM416 260q0 51.75-15.25
82.75-9.5 19.25-26.375 33.25t-35.25 21.5-42.5 11.875-42.875 5.5-41.75
1.125q-19.5 0-35.5-0.75t-36.875-3.125-38.125-7.5-34.25-12.875-30.25-20.25-21.5-28.75q-15.5-30.75-15.5-82.75
0-59.25 34-99-6.75-20.5-6.75-42.5 0-29 12.75-54.5 27 0 47.5 9.875t47.25
30.875q36.75-8.75 77.25-8.75 37 0 70 8 26.25-20.5
46.75-30.25t47.25-9.75q12.75 25.5 12.75 54.5 0 21.75-6.75 42 34 40 34
99.5z" />
</svg>
</defs>
</svg>
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="search" autocomplete="off">
<label class="md-overlay" data-md-component="overlay" for="drawer"></label>
<a href="#get-started-with-github" tabindex="1" class="md-skip">
Skip to content
</a>
<header class="md-header" data-md-component="header">
<nav class="md-header-nav md-grid">
<div class="md-flex">
<div class="md-flex__cell md-flex__cell--shrink">
<a href="https://pages.charlesreid1.com/github-heroku-attack-rabbits" title="github-heroku-attack-rabbits" class="md-header-nav__button md-logo">
<img src="../img/bunny.png" width="24" height="24">
</a>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--menu md-header-nav__button" for="drawer"></label>
</div>
<div class="md-flex__cell md-flex__cell--stretch">
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
<span class="md-header-nav__topic">
github-heroku-attack-rabbits
</span>
<span class="md-header-nav__topic">
Get Started with Github
</span>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--search md-header-nav__button" for="search"></label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="query" data-md-state="active">
<label class="md-icon md-search__icon" for="search"></label>
<button type="reset" class="md-icon md-search__icon" data-md-component="reset" tabindex="-1">
&#xE5CD;
</button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="result">
<div class="md-search-result__meta">
Type to start searching
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<div class="md-header-nav__source">
<a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
charlesreid1/github-heroku-attack-rabbits
</div>
</a>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container">
<main class="md-main">
<div class="md-main__inner md-grid" data-md-component="container">
<div class="md-sidebar md-sidebar--primary" data-md-component="navigation">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" data-md-level="0">
<label class="md-nav__title md-nav__title--site" for="drawer">
<span class="md-nav__button md-logo">
<img src="../img/bunny.png" width="48" height="48">
</span>
github-heroku-attack-rabbits
</label>
<div class="md-nav__source">
<a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
charlesreid1/github-heroku-attack-rabbits
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href=".." title="Index" class="md-nav__link">
Index
</a>
</li>
<li class="md-nav__item">
<a href="../heroku/" title="Get Started with Heroku" class="md-nav__link">
Get Started with Heroku
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-toggle md-nav__toggle" data-md-toggle="toc" type="checkbox" id="toc">
<label class="md-nav__link md-nav__link--active" for="toc">
Get Started with Github
</label>
<a href="./" title="Get Started with Github" class="md-nav__link md-nav__link--active">
Get Started with Github
</a>
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#get-started-with-github" title="Get started with Github" class="md-nav__link">
Get started with Github
</a>
<nav class="md-nav">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#creating-github-oauth-app" title="Creating Github OAuth App" class="md-nav__link">
Creating Github OAuth App
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#values-to-use" title="Values to use" class="md-nav__link">
Values to use
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../repo/" title="Initialize Repository: Branches" class="md-nav__link">
Initialize Repository: Branches
</a>
</li>
<li class="md-nav__item">
<a href="../flask/" title="Create a Flask App using Flask-Dance" class="md-nav__link">
Create a Flask App using Flask-Dance
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-6" type="checkbox" id="nav-6">
<label class="md-nav__link" for="nav-6">
Flask
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-6">
Flask
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../flask_auth_github/" title="Authenticate users based on Github membership only" class="md-nav__link">
Authenticate users based on Github membership only
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_org/" title="Authenticate users based on organization or team membership" class="md-nav__link">
Authenticate users based on organization or team membership
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_other/" title="Authenticate users based on some other criteria" class="md-nav__link">
Authenticate users based on some other criteria
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_portions/" title="Protection portions of the site" class="md-nav__link">
Protection portions of the site
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../flask_local/" title="Test Flask App Locally" class="md-nav__link">
Test Flask App Locally
</a>
</li>
<li class="md-nav__item">
<a href="../flask_heroku/" title="Deploying Flask App to Heroku" class="md-nav__link">
Deploying Flask App to Heroku
</a>
</li>
<li class="md-nav__item">
<a href="../custom_domains/" title="Custom Domains" class="md-nav__link">
Custom Domains
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="toc">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#get-started-with-github" title="Get started with Github" class="md-nav__link">
Get started with Github
</a>
<nav class="md-nav">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#creating-github-oauth-app" title="Creating Github OAuth App" class="md-nav__link">
Creating Github OAuth App
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#values-to-use" title="Values to use" class="md-nav__link">
Values to use
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content">
<article class="md-content__inner md-typeset">
<h1>Get Started with Github</h1>
<h2 id="get-started-with-github">Get started with Github</h2>
<p>We mentioned on the <a href="../heroku/">heroku</a> page that heroku
creates a remote git repository to hold the files you
want to host.</p>
<p>To use the contents of a Github repository on Heroku,
just treat it like another git remote, no special setup
is needed.</p>
<p>However, to set up your Github-Heroku attack rabbits to
authenticate a user via Github, and mercilessly attack
all intruders, you must create a Github OAuth App.</p>
<h3 id="creating-github-oauth-app">Creating Github OAuth App</h3>
<p>Log into Github</p>
<p>Go to Settings</p>
<p>Click "Developer Settings" on the left side</p>
<p>Click "New OAuth App" button in upper right</p>
<p><strong>What do these settings mean?</strong></p>
<ul>
<li>
<p><strong>Application name</strong> is what will be shown to users when they visit
a page protected by the attack rabbits and are prompted for
their password by Github.</p>
</li>
<li>
<p><strong>Homepage URL/Application description</strong> are for users who want to know more
about your killer attack rabbit Github app</p>
</li>
<li>
<p><strong>Authorization callback URL</strong> is the URL that the users will be sent to
once they authenticate with Github and they are granted an OAuth token.
This is the magic ingredient that allows you to take actions on behalf
of the account logging in.</p>
</li>
</ul>
<p>In this guide we'll cover the case of checking membership in organizations or teams,
but what your attack rabbits end up doing to determine if a user is allowed to
access your secret pages is up to you.</p>
<h2 id="values-to-use">Values to use</h2>
<p>You should set your own values for the <strong>name</strong> and <strong>description</strong> fields.</p>
<p>The <strong>home URL</strong> is not actually necessary - it is simply provided for users to
get more information about your app.</p>
<p>The most important is the <strong>callback URL</strong>, which should be set to:</p>
<pre><code>http://localhost:5000/login/github/authorized
</code></pre>
<p>This is for testing locally <em>only</em>.</p>
<p>Don't use HTTPS in the callback URL!</p>
</article>
</div>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-nav">
<nav class="md-footer-nav__inner md-grid">
<a href="../heroku/" title="Get Started with Heroku" class="md-flex md-footer-nav__link md-footer-nav__link--prev" rel="prev">
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-back md-footer-nav__button"></i>
</div>
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Previous
</span>
Get Started with Heroku
</span>
</div>
</a>
<a href="../repo/" title="Initialize Repository: Branches" class="md-flex md-footer-nav__link md-footer-nav__link--next" rel="next">
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Next
</span>
Initialize Repository: Branches
</span>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>
</div>
</a>
</nav>
</div>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-footer-copyright">
<div class="md-footer-copyright__highlight">
Copyright &copy; 2018 Charles Reid, released under the <a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/docs/LICENSE">WTFPL</a>.<br /><br />Many Bothans died to bring us this documentation.<br /><br />
</div>
powered by
<a href="http://www.mkdocs.org">MkDocs</a>
and
<a href="https://squidfunk.github.io/mkdocs-material/">
Material for MkDocs</a>
</div>
</div>
</div>
</footer>
</div>
<script src="../assets/javascripts/application.0cf9b500.js"></script>
<script>app.initialize({version:"0.17.3",url:{base:".."}})</script>
<script src="../search/require.js"></script>
<script src="../search/search.js"></script>
</body>
</html>

676
heroku/index.html

@ -0,0 +1,676 @@ @@ -0,0 +1,676 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<link rel="canonical" href="https://pages.charlesreid1.com/github-heroku-attack-rabbits/heroku/">
<meta name="lang:clipboard.copy" content="Copy to clipboard">
<meta name="lang:clipboard.copied" content="Copied to clipboard">
<meta name="lang:search.language" content="en">
<meta name="lang:search.pipeline.stopwords" content="True">
<meta name="lang:search.pipeline.trimmer" content="True">
<meta name="lang:search.result.none" content="No matching documents">
<meta name="lang:search.result.one" content="1 matching document">
<meta name="lang:search.result.other" content="# matching documents">
<meta name="lang:search.tokenizer" content="[\s\-]+">
<link rel="shortcut icon" href="../">
<meta name="generator" content="mkdocs-0.17.3, mkdocs-material-2.7.2">
<title>Get Started with Heroku - github-heroku-attack-rabbits</title>
<link rel="stylesheet" href="../assets/stylesheets/application.8d40d89b.css">
<link rel="stylesheet" href="../assets/stylesheets/application-palette.6079476c.css">
<script src="../assets/javascripts/modernizr.1aa3b519.js"></script>
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Questrial:300,400,400i,700|Roboto+Mono">
<style>body,input{font-family:"Questrial","Helvetica Neue",Helvetica,Arial,sans-serif}code,kbd,pre{font-family:"Roboto Mono","Courier New",Courier,monospace}</style>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="../css/custom.css">
</head>
<body dir="ltr" data-md-color-primary="red" data-md-color-accent="red">
<svg class="md-svg">
<defs>
<svg xmlns="http://www.w3.org/2000/svg" width="416" height="448"
viewBox="0 0 416 448" id="github">
<path fill="currentColor" d="M160 304q0 10-3.125 20.5t-10.75 19-18.125
8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19 18.125-8.5
18.125 8.5 10.75 19 3.125 20.5zM320 304q0 10-3.125 20.5t-10.75
19-18.125 8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19
18.125-8.5 18.125 8.5 10.75 19 3.125 20.5zM360
304q0-30-17.25-51t-46.75-21q-10.25 0-48.75 5.25-17.75 2.75-39.25
2.75t-39.25-2.75q-38-5.25-48.75-5.25-29.5 0-46.75 21t-17.25 51q0 22 8
38.375t20.25 25.75 30.5 15 35 7.375 37.25 1.75h42q20.5 0
37.25-1.75t35-7.375 30.5-15 20.25-25.75 8-38.375zM416 260q0 51.75-15.25
82.75-9.5 19.25-26.375 33.25t-35.25 21.5-42.5 11.875-42.875 5.5-41.75
1.125q-19.5 0-35.5-0.75t-36.875-3.125-38.125-7.5-34.25-12.875-30.25-20.25-21.5-28.75q-15.5-30.75-15.5-82.75
0-59.25 34-99-6.75-20.5-6.75-42.5 0-29 12.75-54.5 27 0 47.5 9.875t47.25
30.875q36.75-8.75 77.25-8.75 37 0 70 8 26.25-20.5
46.75-30.25t47.25-9.75q12.75 25.5 12.75 54.5 0 21.75-6.75 42 34 40 34
99.5z" />
</svg>
</defs>
</svg>
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="search" autocomplete="off">
<label class="md-overlay" data-md-component="overlay" for="drawer"></label>
<a href="#create-a-heroku-app" tabindex="1" class="md-skip">
Skip to content
</a>
<header class="md-header" data-md-component="header">
<nav class="md-header-nav md-grid">
<div class="md-flex">
<div class="md-flex__cell md-flex__cell--shrink">
<a href="https://pages.charlesreid1.com/github-heroku-attack-rabbits" title="github-heroku-attack-rabbits" class="md-header-nav__button md-logo">
<img src="../img/bunny.png" width="24" height="24">
</a>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--menu md-header-nav__button" for="drawer"></label>
</div>
<div class="md-flex__cell md-flex__cell--stretch">
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
<span class="md-header-nav__topic">
github-heroku-attack-rabbits
</span>
<span class="md-header-nav__topic">
Get Started with Heroku
</span>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--search md-header-nav__button" for="search"></label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="query" data-md-state="active">
<label class="md-icon md-search__icon" for="search"></label>
<button type="reset" class="md-icon md-search__icon" data-md-component="reset" tabindex="-1">
&#xE5CD;
</button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="result">
<div class="md-search-result__meta">
Type to start searching
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<div class="md-header-nav__source">
<a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
charlesreid1/github-heroku-attack-rabbits
</div>
</a>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container">
<main class="md-main">
<div class="md-main__inner md-grid" data-md-component="container">
<div class="md-sidebar md-sidebar--primary" data-md-component="navigation">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" data-md-level="0">
<label class="md-nav__title md-nav__title--site" for="drawer">
<span class="md-nav__button md-logo">
<img src="../img/bunny.png" width="48" height="48">
</span>
github-heroku-attack-rabbits
</label>
<div class="md-nav__source">
<a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
charlesreid1/github-heroku-attack-rabbits
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href=".." title="Index" class="md-nav__link">
Index
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-toggle md-nav__toggle" data-md-toggle="toc" type="checkbox" id="toc">
<label class="md-nav__link md-nav__link--active" for="toc">
Get Started with Heroku
</label>
<a href="./" title="Get Started with Heroku" class="md-nav__link md-nav__link--active">
Get Started with Heroku
</a>
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#before-you-begin-install-heroku-toolbelt" title="Before you begin: install Heroku toolbelt" class="md-nav__link">
Before you begin: install Heroku toolbelt
</a>
</li>
<li class="md-nav__item">
<a href="#creating-a-heroku-app" title="Creating a Heroku app" class="md-nav__link">
Creating a Heroku app
</a>
</li>
<li class="md-nav__item">
<a href="#where-heroku-apps-live" title="Where Heroku apps live" class="md-nav__link">
Where Heroku apps live
</a>
<nav class="md-nav">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#how-heroku-apps-work" title="How Heroku apps work" class="md-nav__link">
How Heroku apps work
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../github/" title="Get Started with Github" class="md-nav__link">
Get Started with Github
</a>
</li>
<li class="md-nav__item">
<a href="../repo/" title="Initialize Repository: Branches" class="md-nav__link">
Initialize Repository: Branches
</a>
</li>
<li class="md-nav__item">
<a href="../flask/" title="Create a Flask App using Flask-Dance" class="md-nav__link">
Create a Flask App using Flask-Dance
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-6" type="checkbox" id="nav-6">
<label class="md-nav__link" for="nav-6">
Flask
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-6">
Flask
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../flask_auth_github/" title="Authenticate users based on Github membership only" class="md-nav__link">
Authenticate users based on Github membership only
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_org/" title="Authenticate users based on organization or team membership" class="md-nav__link">
Authenticate users based on organization or team membership
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_other/" title="Authenticate users based on some other criteria" class="md-nav__link">
Authenticate users based on some other criteria
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_portions/" title="Protection portions of the site" class="md-nav__link">
Protection portions of the site
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../flask_local/" title="Test Flask App Locally" class="md-nav__link">
Test Flask App Locally
</a>
</li>
<li class="md-nav__item">
<a href="../flask_heroku/" title="Deploying Flask App to Heroku" class="md-nav__link">
Deploying Flask App to Heroku
</a>
</li>
<li class="md-nav__item">
<a href="../custom_domains/" title="Custom Domains" class="md-nav__link">
Custom Domains
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="toc">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#before-you-begin-install-heroku-toolbelt" title="Before you begin: install Heroku toolbelt" class="md-nav__link">
Before you begin: install Heroku toolbelt
</a>
</li>
<li class="md-nav__item">
<a href="#creating-a-heroku-app" title="Creating a Heroku app" class="md-nav__link">
Creating a Heroku app
</a>
</li>
<li class="md-nav__item">
<a href="#where-heroku-apps-live" title="Where Heroku apps live" class="md-nav__link">
Where Heroku apps live
</a>
<nav class="md-nav">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#how-heroku-apps-work" title="How Heroku apps work" class="md-nav__link">
How Heroku apps work
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content">
<article class="md-content__inner md-typeset">
<h1 id="create-a-heroku-app">Create a Heroku app</h1>
<h2 id="before-you-begin-install-heroku-toolbelt">Before you begin: install Heroku toolbelt</h2>
<p>Heroku offers a really nice command line interface tool called
Heroku Toolbelt. It is available through Homebrew and Aptitude:</p>
<pre><code class="plain">$ brew install Heroku # from Mac
$ apt-get install Heroku # from Ubuntu
</code></pre>
<p>It will then be available on the command line as <code>Heroku</code>.</p>
<p>The first thing you should do is authenticate with
your Heroku account by running</p>
<pre><code class="plain">$ heroku login
</code></pre>
<p>We will use this command line application for the following tasks:</p>
<ul>
<li>Create a git remote to point to the right Heroku git remote location</li>
<li>Set environment variables (for e.g. secret keys) on the remote Heroku instance</li>
<li>Get information (logs, status, etc.) about your Heroku app</li>
</ul>
<p>We will cover these commands as they come up.</p>
<h2 id="creating-a-heroku-app">Creating a Heroku app</h2>
<p>Start by creating a Heroku app.</p>
<ul>
<li>Each Heroku app must have a unique name</li>
<li>Each Heroku app creates a remote git repo</li>
<li>Master branch is what Heroku deploys publicly on Herokuapps.com</li>
<li>You will also need Heroku CLI to link your github repo to your Heroku app</li>
</ul>
<h2 id="where-heroku-apps-live">Where Heroku apps live</h2>
<p>Suppose you are creating an app called <code>my-cool-app</code>
on Heroku. Then your application will be hosted by
Heroku and will be available at the URL:</p>
<pre><code class="plain">https://my-cool-app.herokuapp.com
</code></pre>
<h3 id="how-heroku-apps-work">How Heroku apps work</h3>
<p>If you have used Github Pages before, Heroku uses a similar
model (live hosting one particular branch of a git repository).
However, Heroku is different because you can run dynamic scripts
using Python, Ruby, PHP, etc.</p>
<p>To change the content of your Heroku app, just change the contents
of the repository, and push to master (push to the master branch of
the remote Heroku repository).</p>
<p>You will need to structure your repository carefully.
That's what this page is here to help you do.
Heroku can figure out the rest from there.</p>
</article>
</div>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-nav">
<nav class="md-footer-nav__inner md-grid">
<a href=".." title="Index" class="md-flex md-footer-nav__link md-footer-nav__link--prev" rel="prev">
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-back md-footer-nav__button"></i>
</div>
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Previous
</span>
Index
</span>
</div>
</a>
<a href="../github/" title="Get Started with Github" class="md-flex md-footer-nav__link md-footer-nav__link--next" rel="next">
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Next
</span>
Get Started with Github
</span>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>
</div>
</a>
</nav>
</div>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-footer-copyright">
<div class="md-footer-copyright__highlight">
Copyright &copy; 2018 Charles Reid, released under the <a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/docs/LICENSE">WTFPL</a>.<br /><br />Many Bothans died to bring us this documentation.<br /><br />
</div>
powered by
<a href="http://www.mkdocs.org">MkDocs</a>
and
<a href="https://squidfunk.github.io/mkdocs-material/">
Material for MkDocs</a>
</div>
</div>
</div>
</footer>
</div>
<script src="../assets/javascripts/application.0cf9b500.js"></script>
<script>app.initialize({version:"0.17.3",url:{base:".."}})</script>
<script src="../search/require.js"></script>
<script src="../search/search.js"></script>
</body>
</html>

0
docs/img/bunny.png → img/bunny.png

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

0
docs/img/warnico.png → img/warnico.png

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

0
docs/img/warning.png → img/warning.png

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 46 KiB

703
index.html

@ -0,0 +1,703 @@ @@ -0,0 +1,703 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<link rel="canonical" href="https://pages.charlesreid1.com/github-heroku-attack-rabbits/">
<meta name="lang:clipboard.copy" content="Copy to clipboard">
<meta name="lang:clipboard.copied" content="Copied to clipboard">
<meta name="lang:search.language" content="en">
<meta name="lang:search.pipeline.stopwords" content="True">
<meta name="lang:search.pipeline.trimmer" content="True">
<meta name="lang:search.result.none" content="No matching documents">
<meta name="lang:search.result.one" content="1 matching document">
<meta name="lang:search.result.other" content="# matching documents">
<meta name="lang:search.tokenizer" content="[\s\-]+">
<link rel="shortcut icon" href="./">
<meta name="generator" content="mkdocs-0.17.3, mkdocs-material-2.7.2">
<title>github-heroku-attack-rabbits</title>
<link rel="stylesheet" href="./assets/stylesheets/application.8d40d89b.css">
<link rel="stylesheet" href="./assets/stylesheets/application-palette.6079476c.css">
<script src="./assets/javascripts/modernizr.1aa3b519.js"></script>
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Questrial:300,400,400i,700|Roboto+Mono">
<style>body,input{font-family:"Questrial","Helvetica Neue",Helvetica,Arial,sans-serif}code,kbd,pre{font-family:"Roboto Mono","Courier New",Courier,monospace}</style>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="./css/custom.css">
</head>
<body dir="ltr" data-md-color-primary="red" data-md-color-accent="red">
<svg class="md-svg">
<defs>
<svg xmlns="http://www.w3.org/2000/svg" width="416" height="448"
viewBox="0 0 416 448" id="github">
<path fill="currentColor" d="M160 304q0 10-3.125 20.5t-10.75 19-18.125
8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19 18.125-8.5
18.125 8.5 10.75 19 3.125 20.5zM320 304q0 10-3.125 20.5t-10.75
19-18.125 8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19
18.125-8.5 18.125 8.5 10.75 19 3.125 20.5zM360
304q0-30-17.25-51t-46.75-21q-10.25 0-48.75 5.25-17.75 2.75-39.25
2.75t-39.25-2.75q-38-5.25-48.75-5.25-29.5 0-46.75 21t-17.25 51q0 22 8
38.375t20.25 25.75 30.5 15 35 7.375 37.25 1.75h42q20.5 0
37.25-1.75t35-7.375 30.5-15 20.25-25.75 8-38.375zM416 260q0 51.75-15.25
82.75-9.5 19.25-26.375 33.25t-35.25 21.5-42.5 11.875-42.875 5.5-41.75
1.125q-19.5 0-35.5-0.75t-36.875-3.125-38.125-7.5-34.25-12.875-30.25-20.25-21.5-28.75q-15.5-30.75-15.5-82.75
0-59.25 34-99-6.75-20.5-6.75-42.5 0-29 12.75-54.5 27 0 47.5 9.875t47.25
30.875q36.75-8.75 77.25-8.75 37 0 70 8 26.25-20.5
46.75-30.25t47.25-9.75q12.75 25.5 12.75 54.5 0 21.75-6.75 42 34 40 34
99.5z" />
</svg>
</defs>
</svg>
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="search" autocomplete="off">
<label class="md-overlay" data-md-component="overlay" for="drawer"></label>
<a href="#github-heroku-attack-rabbits" tabindex="1" class="md-skip">
Skip to content
</a>
<header class="md-header" data-md-component="header">
<nav class="md-header-nav md-grid">
<div class="md-flex">
<div class="md-flex__cell md-flex__cell--shrink">
<a href="https://pages.charlesreid1.com/github-heroku-attack-rabbits" title="github-heroku-attack-rabbits" class="md-header-nav__button md-logo">
<img src="./img/bunny.png" width="24" height="24">
</a>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--menu md-header-nav__button" for="drawer"></label>
</div>
<div class="md-flex__cell md-flex__cell--stretch">
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
<span class="md-header-nav__topic">
github-heroku-attack-rabbits
</span>
<span class="md-header-nav__topic">
Index
</span>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--search md-header-nav__button" for="search"></label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="query" data-md-state="active">
<label class="md-icon md-search__icon" for="search"></label>
<button type="reset" class="md-icon md-search__icon" data-md-component="reset" tabindex="-1">
&#xE5CD;
</button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="result">
<div class="md-search-result__meta">
Type to start searching
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<div class="md-header-nav__source">
<a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
charlesreid1/github-heroku-attack-rabbits
</div>
</a>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container">
<main class="md-main">
<div class="md-main__inner md-grid" data-md-component="container">
<div class="md-sidebar md-sidebar--primary" data-md-component="navigation">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" data-md-level="0">
<label class="md-nav__title md-nav__title--site" for="drawer">
<span class="md-nav__button md-logo">
<img src="./img/bunny.png" width="48" height="48">
</span>
github-heroku-attack-rabbits
</label>
<div class="md-nav__source">
<a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
charlesreid1/github-heroku-attack-rabbits
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--active">
<input class="md-toggle md-nav__toggle" data-md-toggle="toc" type="checkbox" id="toc">
<label class="md-nav__link md-nav__link--active" for="toc">
Index
</label>
<a href="." title="Index" class="md-nav__link md-nav__link--active">
Index
</a>
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#whats-this-business-all-about-then" title="What's this business all about, then?" class="md-nav__link">
What's this business all about, then?
</a>
</li>
<li class="md-nav__item">
<a href="#where-is-everything" title="Where is everything?" class="md-nav__link">
Where is everything?
</a>
</li>
<li class="md-nav__item">
<a href="#contents" title="Contents" class="md-nav__link">
Contents
</a>
</li>
<li class="md-nav__item">
<a href="#links" title="Links" class="md-nav__link">
Links
</a>
</li>
<li class="md-nav__item">
<a href="#license" title="License" class="md-nav__link">
License
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="heroku/" title="Get Started with Heroku" class="md-nav__link">
Get Started with Heroku
</a>
</li>
<li class="md-nav__item">
<a href="github/" title="Get Started with Github" class="md-nav__link">
Get Started with Github
</a>
</li>
<li class="md-nav__item">
<a href="repo/" title="Initialize Repository: Branches" class="md-nav__link">
Initialize Repository: Branches
</a>
</li>
<li class="md-nav__item">
<a href="flask/" title="Create a Flask App using Flask-Dance" class="md-nav__link">
Create a Flask App using Flask-Dance
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-6" type="checkbox" id="nav-6">
<label class="md-nav__link" for="nav-6">
Flask
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-6">
Flask
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="flask_auth_github/" title="Authenticate users based on Github membership only" class="md-nav__link">
Authenticate users based on Github membership only
</a>
</li>
<li class="md-nav__item">
<a href="flask_auth_org/" title="Authenticate users based on organization or team membership" class="md-nav__link">
Authenticate users based on organization or team membership
</a>
</li>
<li class="md-nav__item">
<a href="flask_auth_other/" title="Authenticate users based on some other criteria" class="md-nav__link">
Authenticate users based on some other criteria
</a>
</li>
<li class="md-nav__item">
<a href="flask_auth_portions/" title="Protection portions of the site" class="md-nav__link">
Protection portions of the site
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="flask_local/" title="Test Flask App Locally" class="md-nav__link">
Test Flask App Locally
</a>
</li>
<li class="md-nav__item">
<a href="flask_heroku/" title="Deploying Flask App to Heroku" class="md-nav__link">
Deploying Flask App to Heroku
</a>
</li>
<li class="md-nav__item">
<a href="custom_domains/" title="Custom Domains" class="md-nav__link">
Custom Domains
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="toc">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#whats-this-business-all-about-then" title="What's this business all about, then?" class="md-nav__link">
What's this business all about, then?
</a>
</li>
<li class="md-nav__item">
<a href="#where-is-everything" title="Where is everything?" class="md-nav__link">
Where is everything?
</a>
</li>
<li class="md-nav__item">
<a href="#contents" title="Contents" class="md-nav__link">
Contents
</a>
</li>
<li class="md-nav__item">
<a href="#links" title="Links" class="md-nav__link">
Links
</a>
</li>
<li class="md-nav__item">
<a href="#license" title="License" class="md-nav__link">
License
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content">
<article class="md-content__inner md-typeset">
<h1 id="github-heroku-attack-rabbits">github-heroku-attack-rabbits</h1>
<h2 id="whats-this-business-all-about-then">What's this business all about, then?</h2>
<p>This repository helps you put access control into place to protect your secret pages by (deep breath):</p>
<p>hosting your secret page of static and/or dynamic content by using a free Heroku app
running a Python Flask server that uses Flask-Dance to authenticate visitors
with Github using OAuth which allows you fine-grained access control for your pages
using user attributes like organization or team membership or even things like how many
vowels a user has in their username. </p>
<p>Also, did I mention the attack rabbits?</p>
<p><img alt="warning: attack rabbits ahead" src="./img/warning.png" /></p>
<h2 id="where-is-everything">Where is everything?</h2>
<p>Final pages:</p>
<ul>
<li>
<p>The finished product (pages on Heroku protected by attack rabbits)
is at <a href="https://github-heroku-attack-rabbits.herokuapp.com">github-heroku-attack-rabbits.herokuapp.com</a></p>
</li>
<li>
<p>The documentation is at <a href="https://pages.charlesreid1.com/github-heroku-attack-rabbits">pages.charlesreid1.com/github-heroku-attack-rabbits</a></p>
</li>
</ul>
<p>Two branches in this repo compose the github-heroku-attack-rabbits documentation:</p>
<ul>
<li>
<p>(<strong>YOU ARE HERE</strong>) The <a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/docs"><code>docs</code></a>
branch contains the files needed to generate the
<a href="https://pages.charlesreid1.com/github-heroku-attack-rabbits">github-heroku-attack-rabbits documentation site</a>.</p>
</li>
<li>
<p>The <a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/gh-pages"><code>gh-pages</code></a>
branch contains the static files generated from the documentation.
The contents of this branch compose the
<a href="https://pages.charlesreid1.com/github-heroku-attack-rabbits">github-heroku-attack-rabbits documentation site</a>.</p>
</li>
</ul>
<p>Two branches illustrate github-heroku-attack-rabbits in practice:</p>
<ul>
<li>
<p>The <a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/secret"><code>secret</code></a>
branch contains the files needed to create the secret page. (This is the
"secret page source branch", so to speak.)
This repository, the one you are looking at right now, is public, so of course
these will not really be secret, but in practice the <code>secret</code> branch would
live in a private repository.</p>
</li>
<li>
<p>The <a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/heroku-pages"><code>heroku-pages</code></a>
branch contains the content that is actually pushed to Heroku - that is,
the final Flask app. This includes the Flask app (Python program), in
addition to files that tell Heroku how to run the app,
plus gunicorn "middleware" scripts, plus the static content that
Flask is supposed to serve up (whatever that happens to be - in our case,
we will cover an mkdocs documentation site that is behind an authentication
layer.).</p>
</li>
</ul>
<h2 id="contents">Contents</h2>
<p>An overview of the steps:</p>
<p><a href="heroku/">Get Started with Heroku</a></p>
<p><a href="github/">Get Started with Github</a></p>
<p><a href="repo/">Initialize Repository: Branches</a></p>
<p><a href="flask/">Create a Flask App using Flask-Dance</a></p>
<ul>
<li><a href="flask_auth_github/">Authenticate users based on Github membership only</a></li>
<li><a href="flask_auth_org/">Authenticate users based on organization or team membership</a></li>
<li><a href="flask_auth_other/">Authenticate users based on some other criteria</a></li>
<li><a href="flask_auth_portions/">Protection portions of the site</a></li>
</ul>
<p><a href="flask_local/">Test Flask App Locally</a></p>
<p><a href="flask_heroku/">Deploying Flask App to Heroku</a></p>
<p><a href="custom_domains/">Custom Domains</a></p>
<h2 id="links">Links</h2>
<p>Python software used:</p>
<ul>
<li><a href="http://flask.pocoo.org/">Flask</a></li>
<li><a href="https://github.com/singingwolfboy/flask-dance">Flask-dance</a></li>
<li><a href="https://github.com/singingwolfboy/flask-dance-github">Flask-dance-github</a></li>
<li><a href="https://github.com/squidfunk/mkdocs-material">mkdocs-material (documentation theme)</a></li>
<li><a href="http://www.mkdocs.org/">mkdocs (documentation)</a></li>
</ul>
<p>Commercial services:</p>
<ul>
<li><a href="https://heroku.com">Heroku</a></li>
<li><a href="https://github.com">Github</a></li>
</ul>
<h2 id="license">License</h2>
<p>This is released under the <a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/docs/LICENSE">WTFPL</a>.</p>
</article>
</div>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-nav">
<nav class="md-footer-nav__inner md-grid">
<a href="heroku/" title="Get Started with Heroku" class="md-flex md-footer-nav__link md-footer-nav__link--next" rel="next">
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Next
</span>
Get Started with Heroku
</span>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>
</div>
</a>
</nav>
</div>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-footer-copyright">
<div class="md-footer-copyright__highlight">
Copyright &copy; 2018 Charles Reid, released under the <a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/docs/LICENSE">WTFPL</a>.<br /><br />Many Bothans died to bring us this documentation.<br /><br />
</div>
powered by
<a href="http://www.mkdocs.org">MkDocs</a>
and
<a href="https://squidfunk.github.io/mkdocs-material/">
Material for MkDocs</a>
</div>
</div>
</div>
</footer>
</div>
<script src="./assets/javascripts/application.0cf9b500.js"></script>
<script>app.initialize({version:"0.17.3",url:{base:"."}})</script>
<script src="./search/require.js"></script>
<script src="./search/search.js"></script>
</body>
</html>

1
mkdocs-material

@ -1 +0,0 @@ @@ -1 +0,0 @@
Subproject commit ff95dcb8463eb5f8f65b14c3d145afae21671ad9

50
mkdocs.yml

@ -1,50 +0,0 @@ @@ -1,50 +0,0 @@
site_name: github-heroku-attack-rabbits
site_url: https://pages.charlesreid1.com/github-heroku-attack-rabbits
repo_name: charlesreid1/github-heroku-attack-rabbits
repo_url: https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits
edit_uri: ""
pages:
- 'Index' : 'index.md'
- 'Get Started with Heroku': 'heroku.md'
- 'Get Started with Github': 'github.md'
- 'Initialize Repository: Branches': 'repo.md'
- 'Create a Flask App using Flask-Dance': 'flask.md'
- 'Flask':
- 'Authenticate users based on Github membership only': 'flask_auth_github.md'
- 'Authenticate users based on organization or team membership': 'flask_auth_org.md'
- 'Authenticate users based on some other criteria': 'flask_auth_other.md'
- 'Protection portions of the site': 'flask_auth_portions.md'
- 'Test Flask App Locally': 'flask_local.md'
- 'Deploying Flask App to Heroku': 'flask_heroku.md'
- 'Custom Domains': 'custom_domains.md'
copyright: 'Copyright &copy; 2018 Charles Reid, released under the <a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/docs/LICENSE">WTFPL</a>.<br /><br />Many Bothans died to bring us this documentation.<br /><br />'
docs_dir: docs
site_dir: site
theme:
name: null
custom_dir: 'mkdocs-material/material'
# pretty colors! see https://squidfunk.github.io/mkdocs-material/getting-started/#primary-colors
palette:
primary: 'blue grey'
accent: 'blue grey'
logo: 'img/bunny.png'
### # fun logos! see https://material.io/icons/
### logo:
### icon: 'lock'
font:
text: 'Questrial'
code: 'Roboto Mono'
# this will add docs/css/custom.css to all your docs
extra_css:
- css/custom.css

676
repo/index.html

@ -0,0 +1,676 @@ @@ -0,0 +1,676 @@
<!DOCTYPE html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<link rel="canonical" href="https://pages.charlesreid1.com/github-heroku-attack-rabbits/repo/">
<meta name="lang:clipboard.copy" content="Copy to clipboard">
<meta name="lang:clipboard.copied" content="Copied to clipboard">
<meta name="lang:search.language" content="en">
<meta name="lang:search.pipeline.stopwords" content="True">
<meta name="lang:search.pipeline.trimmer" content="True">
<meta name="lang:search.result.none" content="No matching documents">
<meta name="lang:search.result.one" content="1 matching document">
<meta name="lang:search.result.other" content="# matching documents">
<meta name="lang:search.tokenizer" content="[\s\-]+">
<link rel="shortcut icon" href="../">
<meta name="generator" content="mkdocs-0.17.3, mkdocs-material-2.7.2">
<title>Initialize Repository: Branches - github-heroku-attack-rabbits</title>
<link rel="stylesheet" href="../assets/stylesheets/application.8d40d89b.css">
<link rel="stylesheet" href="../assets/stylesheets/application-palette.6079476c.css">
<script src="../assets/javascripts/modernizr.1aa3b519.js"></script>
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Questrial:300,400,400i,700|Roboto+Mono">
<style>body,input{font-family:"Questrial","Helvetica Neue",Helvetica,Arial,sans-serif}code,kbd,pre{font-family:"Roboto Mono","Courier New",Courier,monospace}</style>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="../css/custom.css">
</head>
<body dir="ltr" data-md-color-primary="red" data-md-color-accent="red">
<svg class="md-svg">
<defs>
<svg xmlns="http://www.w3.org/2000/svg" width="416" height="448"
viewBox="0 0 416 448" id="github">
<path fill="currentColor" d="M160 304q0 10-3.125 20.5t-10.75 19-18.125
8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19 18.125-8.5
18.125 8.5 10.75 19 3.125 20.5zM320 304q0 10-3.125 20.5t-10.75
19-18.125 8.5-18.125-8.5-10.75-19-3.125-20.5 3.125-20.5 10.75-19
18.125-8.5 18.125 8.5 10.75 19 3.125 20.5zM360
304q0-30-17.25-51t-46.75-21q-10.25 0-48.75 5.25-17.75 2.75-39.25
2.75t-39.25-2.75q-38-5.25-48.75-5.25-29.5 0-46.75 21t-17.25 51q0 22 8
38.375t20.25 25.75 30.5 15 35 7.375 37.25 1.75h42q20.5 0
37.25-1.75t35-7.375 30.5-15 20.25-25.75 8-38.375zM416 260q0 51.75-15.25
82.75-9.5 19.25-26.375 33.25t-35.25 21.5-42.5 11.875-42.875 5.5-41.75
1.125q-19.5 0-35.5-0.75t-36.875-3.125-38.125-7.5-34.25-12.875-30.25-20.25-21.5-28.75q-15.5-30.75-15.5-82.75
0-59.25 34-99-6.75-20.5-6.75-42.5 0-29 12.75-54.5 27 0 47.5 9.875t47.25
30.875q36.75-8.75 77.25-8.75 37 0 70 8 26.25-20.5
46.75-30.25t47.25-9.75q12.75 25.5 12.75 54.5 0 21.75-6.75 42 34 40 34
99.5z" />
</svg>
</defs>
</svg>
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="search" autocomplete="off">
<label class="md-overlay" data-md-component="overlay" for="drawer"></label>
<a href="#initialize-git-repository" tabindex="1" class="md-skip">
Skip to content
</a>
<header class="md-header" data-md-component="header">
<nav class="md-header-nav md-grid">
<div class="md-flex">
<div class="md-flex__cell md-flex__cell--shrink">
<a href="https://pages.charlesreid1.com/github-heroku-attack-rabbits" title="github-heroku-attack-rabbits" class="md-header-nav__button md-logo">
<img src="../img/bunny.png" width="24" height="24">
</a>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--menu md-header-nav__button" for="drawer"></label>
</div>
<div class="md-flex__cell md-flex__cell--stretch">
<div class="md-flex__ellipsis md-header-nav__title" data-md-component="title">
<span class="md-header-nav__topic">
github-heroku-attack-rabbits
</span>
<span class="md-header-nav__topic">
Initialize Repository: Branches
</span>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<label class="md-icon md-icon--search md-header-nav__button" for="search"></label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="query" data-md-state="active">
<label class="md-icon md-search__icon" for="search"></label>
<button type="reset" class="md-icon md-search__icon" data-md-component="reset" tabindex="-1">
&#xE5CD;
</button>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="result">
<div class="md-search-result__meta">
Type to start searching
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<div class="md-header-nav__source">
<a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
charlesreid1/github-heroku-attack-rabbits
</div>
</a>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container">
<main class="md-main">
<div class="md-main__inner md-grid" data-md-component="container">
<div class="md-sidebar md-sidebar--primary" data-md-component="navigation">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" data-md-level="0">
<label class="md-nav__title md-nav__title--site" for="drawer">
<span class="md-nav__button md-logo">
<img src="../img/bunny.png" width="48" height="48">
</span>
github-heroku-attack-rabbits
</label>
<div class="md-nav__source">
<a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits" title="Go to repository" class="md-source" data-md-source="github">
<div class="md-source__icon">
<svg viewBox="0 0 24 24" width="24" height="24">
<use xlink:href="#github" width="24" height="24"></use>
</svg>
</div>
<div class="md-source__repository">
charlesreid1/github-heroku-attack-rabbits
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href=".." title="Index" class="md-nav__link">
Index
</a>
</li>
<li class="md-nav__item">
<a href="../heroku/" title="Get Started with Heroku" class="md-nav__link">
Get Started with Heroku
</a>
</li>
<li class="md-nav__item">
<a href="../github/" title="Get Started with Github" class="md-nav__link">
Get Started with Github
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-toggle md-nav__toggle" data-md-toggle="toc" type="checkbox" id="toc">
<label class="md-nav__link md-nav__link--active" for="toc">
Initialize Repository: Branches
</label>
<a href="./" title="Initialize Repository: Branches" class="md-nav__link md-nav__link--active">
Initialize Repository: Branches
</a>
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#branches" title="Branches" class="md-nav__link">
Branches
</a>
</li>
<li class="md-nav__item">
<a href="#repo-layout" title="Repo Layout" class="md-nav__link">
Repo Layout
</a>
</li>
<li class="md-nav__item">
<a href="#workflow" title="Workflow" class="md-nav__link">
Workflow
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../flask/" title="Create a Flask App using Flask-Dance" class="md-nav__link">
Create a Flask App using Flask-Dance
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-toggle md-nav__toggle" data-md-toggle="nav-6" type="checkbox" id="nav-6">
<label class="md-nav__link" for="nav-6">
Flask
</label>
<nav class="md-nav" data-md-component="collapsible" data-md-level="1">
<label class="md-nav__title" for="nav-6">
Flask
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../flask_auth_github/" title="Authenticate users based on Github membership only" class="md-nav__link">
Authenticate users based on Github membership only
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_org/" title="Authenticate users based on organization or team membership" class="md-nav__link">
Authenticate users based on organization or team membership
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_other/" title="Authenticate users based on some other criteria" class="md-nav__link">
Authenticate users based on some other criteria
</a>
</li>
<li class="md-nav__item">
<a href="../flask_auth_portions/" title="Protection portions of the site" class="md-nav__link">
Protection portions of the site
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../flask_local/" title="Test Flask App Locally" class="md-nav__link">
Test Flask App Locally
</a>
</li>
<li class="md-nav__item">
<a href="../flask_heroku/" title="Deploying Flask App to Heroku" class="md-nav__link">
Deploying Flask App to Heroku
</a>
</li>
<li class="md-nav__item">
<a href="../custom_domains/" title="Custom Domains" class="md-nav__link">
Custom Domains
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="toc">
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary">
<label class="md-nav__title" for="toc">Table of contents</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="#branches" title="Branches" class="md-nav__link">
Branches
</a>
</li>
<li class="md-nav__item">
<a href="#repo-layout" title="Repo Layout" class="md-nav__link">
Repo Layout
</a>
</li>
<li class="md-nav__item">
<a href="#workflow" title="Workflow" class="md-nav__link">
Workflow
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content">
<article class="md-content__inner md-typeset">
<h1 id="initialize-git-repository">Initialize Git Repository</h1>
<p>Let's talk through how a repository should be laid out
if we're going to be hosting a Flask app on Heroku.</p>
<h2 id="branches">Branches</h2>
<p>We will need a minimum of two branches. Here we specify
the names that these branches will have in your Github repo,
<strong>which is different from the names of the branches on Heroku</strong>:</p>
<p>Branches on Github:</p>
<ul>
<li>
<p><code>heroku-pages</code> - this branch contains the content that Heroku will host.
Specifically, it contains the Flask application in a <code>.py</code> file,
and a few other files to help Heroku determine how to run the app
and what to install.</p>
</li>
<li>
<p><code>master</code> - this branch contains the content used to generate the documentation
and page content that is being hosted behind the Heroku attack sheep.
The documentation you are reading right now is from the master branch,
and was made with <code>mkdocs</code>.</p>
</li>
</ul>
<p>On Heroku, we only have a single branch:</p>
<ul>
<li><code>master</code> (Heroku) maps to <code>heroku-pages</code> (Github)</li>
</ul>
<h2 id="repo-layout">Repo Layout</h2>
<p>Let's talk about the layout of the repository.</p>
<p>If you wish to build the site in order to deploy it to Heroku,
you should clone the <code>master</code> branch (preparing to make the
content for your attack sheep-protected page):</p>
<pre><code class="plain">$ git clone -b master https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits.git
$ cd github-heroku-attack-rabbits
</code></pre>
<p>Once you are <em>inside</em> the master branch, clone the repo again,
but this time clone the <code>heroku-pages</code> branch, and clone it
to the <code>site/</code> folder:</p>
<pre><code class="plain">$ git clone -b heroku-pages https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits.git site
$ cd site
</code></pre>
<p>Now you will want to set up the Heroku remote:</p>
<pre><code class="plain">$ heroku git:remote -a my-cool-project
</code></pre>
<p>The layout should now be:</p>
<pre><code class="plain">my-cool-project-repo/ &lt;-- my-cool-project repo pointing to master branch
docs/ \
index.md |
heroku.md | &lt;-- mkdocs files
... | (can use any static content generator:
| pelican, sphinx, etc.)
mkdocs.yml /
site/ &lt;-- my-cool-project repo pointing to heroku-pages branch
Procfile \
github.py | &lt;-- heroku python app files
requirements.txt | (can also use ruby, php, js, etc.)
runtime.txt | (can also use ruby, php, js, etc.)
... /
content/ \
index.html | &lt;-- static content hosted by Flask
sitemap.xml |
... /
</code></pre>
<h2 id="workflow">Workflow</h2>
<p>Once you have things set up according to the instructions and diagram above,
you're ready to run the push-to-deploy workflow and start running your secret
site on Heroku.</p>
</article>
</div>
</div>
</main>
<footer class="md-footer">
<div class="md-footer-nav">
<nav class="md-footer-nav__inner md-grid">
<a href="../github/" title="Get Started with Github" class="md-flex md-footer-nav__link md-footer-nav__link--prev" rel="prev">
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-back md-footer-nav__button"></i>
</div>
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Previous
</span>
Get Started with Github
</span>
</div>
</a>
<a href="../flask/" title="Create a Flask App using Flask-Dance" class="md-flex md-footer-nav__link md-footer-nav__link--next" rel="next">
<div class="md-flex__cell md-flex__cell--stretch md-footer-nav__title">
<span class="md-flex__ellipsis">
<span class="md-footer-nav__direction">
Next
</span>
Create a Flask App using Flask-Dance
</span>
</div>
<div class="md-flex__cell md-flex__cell--shrink">
<i class="md-icon md-icon--arrow-forward md-footer-nav__button"></i>
</div>
</a>
</nav>
</div>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-footer-copyright">
<div class="md-footer-copyright__highlight">
Copyright &copy; 2018 Charles Reid, released under the <a href="https://git.charlesreid1.com/charlesreid1/github-heroku-attack-rabbits/src/branch/docs/LICENSE">WTFPL</a>.<br /><br />Many Bothans died to bring us this documentation.<br /><br />
</div>
powered by
<a href="http://www.mkdocs.org">MkDocs</a>
and
<a href="https://squidfunk.github.io/mkdocs-material/">
Material for MkDocs</a>
</div>
</div>
</div>
</footer>
</div>
<script src="../assets/javascripts/application.0cf9b500.js"></script>
<script>app.initialize({version:"0.17.3",url:{base:".."}})</script>
<script src="../search/require.js"></script>
<script src="../search/search.js"></script>
</body>
</html>

7
search/lunr.min.js vendored

File diff suppressed because one or more lines are too long

1
search/mustache.min.js vendored

File diff suppressed because one or more lines are too long

36
search/require.js

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
/*
RequireJS 2.1.16 Copyright (c) 2010-2015, The Dojo Foundation All Rights Reserved.
Available via the MIT or new BSD license.
see: http://github.com/jrburke/requirejs for details
*/
var requirejs,require,define;
(function(ba){function G(b){return"[object Function]"===K.call(b)}function H(b){return"[object Array]"===K.call(b)}function v(b,c){if(b){var d;for(d=0;d<b.length&&(!b[d]||!c(b[d],d,b));d+=1);}}function T(b,c){if(b){var d;for(d=b.length-1;-1<d&&(!b[d]||!c(b[d],d,b));d-=1);}}function t(b,c){return fa.call(b,c)}function m(b,c){return t(b,c)&&b[c]}function B(b,c){for(var d in b)if(t(b,d)&&c(b[d],d))break}function U(b,c,d,e){c&&B(c,function(c,g){if(d||!t(b,g))e&&"object"===typeof c&&c&&!H(c)&&!G(c)&&!(c instanceof
RegExp)?(b[g]||(b[g]={}),U(b[g],c,d,e)):b[g]=c});return b}function u(b,c){return function(){return c.apply(b,arguments)}}function ca(b){throw b;}function da(b){if(!b)return b;var c=ba;v(b.split("."),function(b){c=c[b]});return c}function C(b,c,d,e){c=Error(c+"\nhttp://requirejs.org/docs/errors.html#"+b);c.requireType=b;c.requireModules=e;d&&(c.originalError=d);return c}function ga(b){function c(a,k,b){var f,l,c,d,e,g,i,p,k=k&&k.split("/"),h=j.map,n=h&&h["*"];if(a){a=a.split("/");l=a.length-1;j.nodeIdCompat&&
Q.test(a[l])&&(a[l]=a[l].replace(Q,""));"."===a[0].charAt(0)&&k&&(l=k.slice(0,k.length-1),a=l.concat(a));l=a;for(c=0;c<l.length;c++)if(d=l[c],"."===d)l.splice(c,1),c-=1;else if(".."===d&&!(0===c||1==c&&".."===l[2]||".."===l[c-1])&&0<c)l.splice(c-1,2),c-=2;a=a.join("/")}if(b&&h&&(k||n)){l=a.split("/");c=l.length;a:for(;0<c;c-=1){e=l.slice(0,c).join("/");if(k)for(d=k.length;0<d;d-=1)if(b=m(h,k.slice(0,d).join("/")))if(b=m(b,e)){f=b;g=c;break a}!i&&(n&&m(n,e))&&(i=m(n,e),p=c)}!f&&i&&(f=i,g=p);f&&(l.splice(0,
g,f),a=l.join("/"))}return(f=m(j.pkgs,a))?f:a}function d(a){z&&v(document.getElementsByTagName("script"),function(k){if(k.getAttribute("data-requiremodule")===a&&k.getAttribute("data-requirecontext")===i.contextName)return k.parentNode.removeChild(k),!0})}function e(a){var k=m(j.paths,a);if(k&&H(k)&&1<k.length)return k.shift(),i.require.undef(a),i.makeRequire(null,{skipMap:!0})([a]),!0}function n(a){var k,c=a?a.indexOf("!"):-1;-1<c&&(k=a.substring(0,c),a=a.substring(c+1,a.length));return[k,a]}function p(a,
k,b,f){var l,d,e=null,g=k?k.name:null,j=a,p=!0,h="";a||(p=!1,a="_@r"+(K+=1));a=n(a);e=a[0];a=a[1];e&&(e=c(e,g,f),d=m(r,e));a&&(e?h=d&&d.normalize?d.normalize(a,function(a){return c(a,g,f)}):-1===a.indexOf("!")?c(a,g,f):a:(h=c(a,g,f),a=n(h),e=a[0],h=a[1],b=!0,l=i.nameToUrl(h)));b=e&&!d&&!b?"_unnormalized"+(O+=1):"";return{prefix:e,name:h,parentMap:k,unnormalized:!!b,url:l,originalName:j,isDefine:p,id:(e?e+"!"+h:h)+b}}function s(a){var k=a.id,b=m(h,k);b||(b=h[k]=new i.Module(a));return b}function q(a,
k,b){var f=a.id,c=m(h,f);if(t(r,f)&&(!c||c.defineEmitComplete))"defined"===k&&b(r[f]);else if(c=s(a),c.error&&"error"===k)b(c.error);else c.on(k,b)}function w(a,b){var c=a.requireModules,f=!1;if(b)b(a);else if(v(c,function(b){if(b=m(h,b))b.error=a,b.events.error&&(f=!0,b.emit("error",a))}),!f)g.onError(a)}function x(){R.length&&(ha.apply(A,[A.length,0].concat(R)),R=[])}function y(a){delete h[a];delete V[a]}function F(a,b,c){var f=a.map.id;a.error?a.emit("error",a.error):(b[f]=!0,v(a.depMaps,function(f,
d){var e=f.id,g=m(h,e);g&&(!a.depMatched[d]&&!c[e])&&(m(b,e)?(a.defineDep(d,r[e]),a.check()):F(g,b,c))}),c[f]=!0)}function D(){var a,b,c=(a=1E3*j.waitSeconds)&&i.startTime+a<(new Date).getTime(),f=[],l=[],g=!1,h=!0;if(!W){W=!0;B(V,function(a){var i=a.map,j=i.id;if(a.enabled&&(i.isDefine||l.push(a),!a.error))if(!a.inited&&c)e(j)?g=b=!0:(f.push(j),d(j));else if(!a.inited&&(a.fetched&&i.isDefine)&&(g=!0,!i.prefix))return h=!1});if(c&&f.length)return a=C("timeout","Load timeout for modules: "+f,null,
f),a.contextName=i.contextName,w(a);h&&v(l,function(a){F(a,{},{})});if((!c||b)&&g)if((z||ea)&&!X)X=setTimeout(function(){X=0;D()},50);W=!1}}function E(a){t(r,a[0])||s(p(a[0],null,!0)).init(a[1],a[2])}function I(a){var a=a.currentTarget||a.srcElement,b=i.onScriptLoad;a.detachEvent&&!Y?a.detachEvent("onreadystatechange",b):a.removeEventListener("load",b,!1);b=i.onScriptError;(!a.detachEvent||Y)&&a.removeEventListener("error",b,!1);return{node:a,id:a&&a.getAttribute("data-requiremodule")}}function J(){var a;
for(x();A.length;){a=A.shift();if(null===a[0])return w(C("mismatch","Mismatched anonymous define() module: "+a[a.length-1]));E(a)}}var W,Z,i,L,X,j={waitSeconds:7,baseUrl:"./",paths:{},bundles:{},pkgs:{},shim:{},config:{}},h={},V={},$={},A=[],r={},S={},aa={},K=1,O=1;L={require:function(a){return a.require?a.require:a.require=i.makeRequire(a.map)},exports:function(a){a.usingExports=!0;if(a.map.isDefine)return a.exports?r[a.map.id]=a.exports:a.exports=r[a.map.id]={}},module:function(a){return a.module?
a.module:a.module={id:a.map.id,uri:a.map.url,config:function(){return m(j.config,a.map.id)||{}},exports:a.exports||(a.exports={})}}};Z=function(a){this.events=m($,a.id)||{};this.map=a;this.shim=m(j.shim,a.id);this.depExports=[];this.depMaps=[];this.depMatched=[];this.pluginMaps={};this.depCount=0};Z.prototype={init:function(a,b,c,f){f=f||{};if(!this.inited){this.factory=b;if(c)this.on("error",c);else this.events.error&&(c=u(this,function(a){this.emit("error",a)}));this.depMaps=a&&a.slice(0);this.errback=
c;this.inited=!0;this.ignore=f.ignore;f.enabled||this.enabled?this.enable():this.check()}},defineDep:function(a,b){this.depMatched[a]||(this.depMatched[a]=!0,this.depCount-=1,this.depExports[a]=b)},fetch:function(){if(!this.fetched){this.fetched=!0;i.startTime=(new Date).getTime();var a=this.map;if(this.shim)i.makeRequire(this.map,{enableBuildCallback:!0})(this.shim.deps||[],u(this,function(){return a.prefix?this.callPlugin():this.load()}));else return a.prefix?this.callPlugin():this.load()}},load:function(){var a=
this.map.url;S[a]||(S[a]=!0,i.load(this.map.id,a))},check:function(){if(this.enabled&&!this.enabling){var a,b,c=this.map.id;b=this.depExports;var f=this.exports,l=this.factory;if(this.inited)if(this.error)this.emit("error",this.error);else{if(!this.defining){this.defining=!0;if(1>this.depCount&&!this.defined){if(G(l)){if(this.events.error&&this.map.isDefine||g.onError!==ca)try{f=i.execCb(c,l,b,f)}catch(d){a=d}else f=i.execCb(c,l,b,f);this.map.isDefine&&void 0===f&&((b=this.module)?f=b.exports:this.usingExports&&
(f=this.exports));if(a)return a.requireMap=this.map,a.requireModules=this.map.isDefine?[this.map.id]:null,a.requireType=this.map.isDefine?"define":"require",w(this.error=a)}else f=l;this.exports=f;if(this.map.isDefine&&!this.ignore&&(r[c]=f,g.onResourceLoad))g.onResourceLoad(i,this.map,this.depMaps);y(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=
this.map,b=a.id,d=p(a.prefix);this.depMaps.push(d);q(d,"defined",u(this,function(f){var l,d;d=m(aa,this.map.id);var e=this.map.name,P=this.map.parentMap?this.map.parentMap.name:null,n=i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(f.normalize&&(e=f.normalize(e,function(a){return c(a,P,!0)})||""),f=p(a.prefix+"!"+e,this.map.parentMap),q(f,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(h,f.id)){this.depMaps.push(f);
if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else d?(this.map.url=i.nameToUrl(d),this.load()):(l=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),l.error=u(this,function(a){this.inited=!0;this.error=a;a.requireModules=[b];B(h,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&y(a.map.id)});w(a)}),l.fromText=u(this,function(f,c){var d=a.name,e=p(d),P=M;c&&(f=c);P&&(M=!1);s(e);t(j.config,b)&&(j.config[d]=j.config[b]);try{g.exec(f)}catch(h){return w(C("fromtexteval",
"fromText eval for "+b+" failed: "+h,h,[b]))}P&&(M=!0);this.depMaps.push(e);i.completeLoad(d);n([d],l)}),f.load(a.name,n,l,j))}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=this;this.enabling=this.enabled=!0;v(this.depMaps,u(this,function(a,b){var c,f;if("string"===typeof a){a=p(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(L,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;q(a,"defined",u(this,function(a){this.defineDep(b,
a);this.check()}));this.errback?q(a,"error",u(this,this.errback)):this.events.error&&q(a,"error",u(this,function(a){this.emit("error",a)}))}c=a.id;f=h[c];!t(L,c)&&(f&&!f.enabled)&&i.enable(a,this)}));B(this.pluginMaps,u(this,function(a){var b=m(h,a.id);b&&!b.enabled&&i.enable(a,this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){v(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:j,contextName:b,
registry:h,defined:r,urlFetched:S,defQueue:A,Module:Z,makeModuleMap:p,nextTick:g.nextTick,onError:w,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=j.shim,c={paths:!0,bundles:!0,config:!0,map:!0};B(a,function(a,b){c[b]?(j[b]||(j[b]={}),U(j[b],a,!0,!0)):j[b]=a});a.bundles&&B(a.bundles,function(a,b){v(a,function(a){a!==b&&(aa[a]=b)})});a.shim&&(B(a.shim,function(a,c){H(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);
b[c]=a}),j.shim=b);a.packages&&v(a.packages,function(a){var b,a="string"===typeof a?{name:a}:a;b=a.name;a.location&&(j.paths[b]=a.location);j.pkgs[b]=a.name+"/"+(a.main||"main").replace(ia,"").replace(Q,"")});B(h,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=p(b))});if(a.deps||a.callback)i.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(ba,arguments));return b||a.exports&&da(a.exports)}},makeRequire:function(a,e){function j(c,d,m){var n,
q;e.enableBuildCallback&&(d&&G(d))&&(d.__requireJsBuild=!0);if("string"===typeof c){if(G(d))return w(C("requireargs","Invalid require call"),m);if(a&&t(L,c))return L[c](h[a.id]);if(g.get)return g.get(i,c,a,j);n=p(c,a,!1,!0);n=n.id;return!t(r,n)?w(C("notloaded",'Module name "'+n+'" has not been loaded yet for context: '+b+(a?"":". Use require([])"))):r[n]}J();i.nextTick(function(){J();q=s(p(null,a));q.skipMap=e.skipMap;q.init(c,d,m,{enabled:!0});D()});return j}e=e||{};U(j,{isBrowser:z,toUrl:function(b){var d,
e=b.lastIndexOf("."),k=b.split("/")[0];if(-1!==e&&(!("."===k||".."===k)||1<e))d=b.substring(e,b.length),b=b.substring(0,e);return i.nameToUrl(c(b,a&&a.id,!0),d,!0)},defined:function(b){return t(r,p(b,a,!1,!0).id)},specified:function(b){b=p(b,a,!1,!0).id;return t(r,b)||t(h,b)}});a||(j.undef=function(b){x();var c=p(b,a,!0),e=m(h,b);d(b);delete r[b];delete S[c.url];delete $[b];T(A,function(a,c){a[0]===b&&A.splice(c,1)});e&&(e.events.defined&&($[b]=e.events),y(b))});return j},enable:function(a){m(h,a.id)&&
s(a).enable()},completeLoad:function(a){var b,c,d=m(j.shim,a)||{},g=d.exports;for(x();A.length;){c=A.shift();if(null===c[0]){c[0]=a;if(b)break;b=!0}else c[0]===a&&(b=!0);E(c)}c=m(h,a);if(!b&&!t(r,a)&&c&&!c.inited){if(j.enforceDefine&&(!g||!da(g)))return e(a)?void 0:w(C("nodefine","No define call for "+a,null,[a]));E([a,d.deps||[],d.exportsFn])}D()},nameToUrl:function(a,b,c){var d,e,h;(d=m(j.pkgs,a))&&(a=d);if(d=m(aa,a))return i.nameToUrl(d,b,c);if(g.jsExtRegExp.test(a))d=a+(b||"");else{d=j.paths;
a=a.split("/");for(e=a.length;0<e;e-=1)if(h=a.slice(0,e).join("/"),h=m(d,h)){H(h)&&(h=h[0]);a.splice(0,e,h);break}d=a.join("/");d+=b||(/^data\:|\?/.test(d)||c?"":".js");d=("/"===d.charAt(0)||d.match(/^[\w\+\.\-]+:/)?"":j.baseUrl)+d}return j.urlArgs?d+((-1===d.indexOf("?")?"?":"&")+j.urlArgs):d},load:function(a,b){g.load(i,a,b)},execCb:function(a,b,c,d){return b.apply(d,c)},onScriptLoad:function(a){if("load"===a.type||ja.test((a.currentTarget||a.srcElement).readyState))N=null,a=I(a),i.completeLoad(a.id)},
onScriptError:function(a){var b=I(a);if(!e(b.id))return w(C("scripterror","Script error for: "+b.id,a,[b.id]))}};i.require=i.makeRequire();return i}var g,x,y,D,I,E,N,J,s,O,ka=/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,la=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,Q=/\.js$/,ia=/^\.\//;x=Object.prototype;var K=x.toString,fa=x.hasOwnProperty,ha=Array.prototype.splice,z=!!("undefined"!==typeof window&&"undefined"!==typeof navigator&&window.document),ea=!z&&"undefined"!==typeof importScripts,ja=
z&&"PLAYSTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/,Y="undefined"!==typeof opera&&"[object Opera]"===opera.toString(),F={},q={},R=[],M=!1;if("undefined"===typeof define){if("undefined"!==typeof requirejs){if(G(requirejs))return;q=requirejs;requirejs=void 0}"undefined"!==typeof require&&!G(require)&&(q=require,require=void 0);g=requirejs=function(b,c,d,e){var n,p="_";!H(b)&&"string"!==typeof b&&(n=b,H(c)?(b=c,c=d,d=e):b=[]);n&&n.context&&(p=n.context);(e=m(F,p))||(e=F[p]=g.s.newContext(p));
n&&e.configure(n);return e.require(b,c,d)};g.config=function(b){return g(b)};g.nextTick="undefined"!==typeof setTimeout?function(b){setTimeout(b,4)}:function(b){b()};require||(require=g);g.version="2.1.16";g.jsExtRegExp=/^\/|:|\?|\.js$/;g.isBrowser=z;x=g.s={contexts:F,newContext:ga};g({});v(["toUrl","undef","defined","specified"],function(b){g[b]=function(){var c=F._;return c.require[b].apply(c,arguments)}});if(z&&(y=x.head=document.getElementsByTagName("head")[0],D=document.getElementsByTagName("base")[0]))y=
x.head=D.parentNode;g.onError=ca;g.createNode=function(b){var c=b.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script");c.type=b.scriptType||"text/javascript";c.charset="utf-8";c.async=!0;return c};g.load=function(b,c,d){var e=b&&b.config||{};if(z)return e=g.createNode(e,c,d),e.setAttribute("data-requirecontext",b.contextName),e.setAttribute("data-requiremodule",c),e.attachEvent&&!(e.attachEvent.toString&&0>e.attachEvent.toString().indexOf("[native code"))&&
!Y?(M=!0,e.attachEvent("onreadystatechange",b.onScriptLoad)):(e.addEventListener("load",b.onScriptLoad,!1),e.addEventListener("error",b.onScriptError,!1)),e.src=d,J=e,D?y.insertBefore(e,D):y.appendChild(e),J=null,e;if(ea)try{importScripts(d),b.completeLoad(c)}catch(m){b.onError(C("importscripts","importScripts failed for "+c+" at "+d,m,[c]))}};z&&!q.skipDataMain&&T(document.getElementsByTagName("script"),function(b){y||(y=b.parentNode);if(I=b.getAttribute("data-main"))return s=I,q.baseUrl||(E=s.split("/"),
s=E.pop(),O=E.length?E.join("/")+"/":"./",q.baseUrl=O),s=s.replace(Q,""),g.jsExtRegExp.test(s)&&(s=I),q.deps=q.deps?q.deps.concat(s):[s],!0});define=function(b,c,d){var e,g;"string"!==typeof b&&(d=c,c=b,b=null);H(c)||(d=c,c=null);!c&&G(d)&&(c=[],d.length&&(d.toString().replace(ka,"").replace(la,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c)));if(M){if(!(e=J))N&&"interactive"===N.readyState||T(document.getElementsByTagName("script"),function(b){if("interactive"===
b.readyState)return N=b}),e=N;e&&(b||(b=e.getAttribute("data-requiremodule")),g=F[e.getAttribute("data-requirecontext")])}(g?g.defQueue:R).push([b,c,d])};define.amd={jQuery:!0};g.exec=function(b){return eval(b)};g(q)}})(this);

4
search/search-results-template.mustache

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
<article>
<h3><a href="{{location}}">{{title}}</a></h3>
<p>{{summary}}</p>
</article>

92
search/search.js

@ -0,0 +1,92 @@ @@ -0,0 +1,92 @@
require.config({
baseUrl: base_url + "/search/"
});
require([
'mustache.min',
'lunr.min',
'text!search-results-template.mustache',
'text!search_index.json',
], function (Mustache, lunr, results_template, data) {
"use strict";
function getSearchTerm()
{
var sPageURL = window.location.search.substring(1);
var sURLVariables = sPageURL.split('&');
for (var i = 0; i < sURLVariables.length; i++)
{
var sParameterName = sURLVariables[i].split('=');
if (sParameterName[0] == 'q')
{
return decodeURIComponent(sParameterName[1].replace(/\+/g, '%20'));
}
}
}
var index = lunr(function () {
this.field('title', {boost: 10});
this.field('text');
this.ref('location');
});
data = JSON.parse(data);
var documents = {};
for (var i=0; i < data.docs.length; i++){
var doc = data.docs[i];
doc.location = base_url + doc.location;
index.add(doc);
documents[doc.location] = doc;
}
var search = function(){
var query = document.getElementById('mkdocs-search-query').value;
var search_results = document.getElementById("mkdocs-search-results");
while (search_results.firstChild) {
search_results.removeChild(search_results.firstChild);
}
if(query === ''){
return;
}
var results = index.search(query);
if (results.length > 0){
for (var i=0; i < results.length; i++){
var result = results[i];
doc = documents[result.ref];
doc.base_url = base_url;
doc.summary = doc.text.substring(0, 200);
var html = Mustache.to_html(results_template, doc);
search_results.insertAdjacentHTML('beforeend', html);
}
} else {
search_results.insertAdjacentHTML('beforeend', "<p>No results found</p>");
}
if(jQuery){
/*
* We currently only automatically hide bootstrap models. This
* requires jQuery to work.
*/
jQuery('#mkdocs_search_modal a').click(function(){
jQuery('#mkdocs_search_modal').modal('hide');
});
}
};
var search_input = document.getElementById('mkdocs-search-query');
var term = getSearchTerm();
if (term){
search_input.value = term;
search();
}
if (search_input){search_input.addEventListener("keyup", search);}
});

229
search/search_index.json

File diff suppressed because one or more lines are too long

390
search/text.js

@ -0,0 +1,390 @@ @@ -0,0 +1,390 @@
/**
* @license RequireJS text 2.0.12 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
* Available via the MIT or new BSD license.
* see: http://github.com/requirejs/text for details
*/
/*jslint regexp: true */
/*global require, XMLHttpRequest, ActiveXObject,
define, window, process, Packages,
java, location, Components, FileUtils */
define(['module'], function (module) {
'use strict';
var text, fs, Cc, Ci, xpcIsWindows,
progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'],
xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im,
bodyRegExp = /<body[^>]*>\s*([\s\S]+)\s*<\/body>/im,
hasLocation = typeof location !== 'undefined' && location.href,
defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\:/, ''),
defaultHostName = hasLocation && location.hostname,
defaultPort = hasLocation && (location.port || undefined),
buildMap = {},
masterConfig = (module.config && module.config()) || {};
text = {
version: '2.0.12',
strip: function (content) {
//Strips <?xml ...?> declarations so that external SVG and XML
//documents can be added to a document without worry. Also, if the string
//is an HTML document, only the part inside the body tag is returned.
if (content) {
content = content.replace(xmlRegExp, "");
var matches = content.match(bodyRegExp);
if (matches) {
content = matches[1];
}
} else {
content = "";
}
return content;
},
jsEscape: function (content) {
return content.replace(/(['\\])/g, '\\$1')
.replace(/[\f]/g, "\\f")
.replace(/[\b]/g, "\\b")
.replace(/[\n]/g, "\\n")
.replace(/[\t]/g, "\\t")
.replace(/[\r]/g, "\\r")
.replace(/[\u2028]/g, "\\u2028")
.replace(/[\u2029]/g, "\\u2029");
},
createXhr: masterConfig.createXhr || function () {
//Would love to dump the ActiveX crap in here. Need IE 6 to die first.
var xhr, i, progId;
if (typeof XMLHttpRequest !== "undefined") {
return new XMLHttpRequest();
} else if (typeof ActiveXObject !== "undefined") {
for (i = 0; i < 3; i += 1) {
progId = progIds[i];
try {
xhr = new ActiveXObject(progId);
} catch (e) {}
if (xhr) {
progIds = [progId]; // so faster next time
break;
}
}
}
return xhr;
},
/**
* Parses a resource name into its component parts. Resource names
* look like: module/name.ext!strip, where the !strip part is
* optional.
* @param {String} name the resource name
* @returns {Object} with properties "moduleName", "ext" and "strip"
* where strip is a boolean.
*/
parseName: function (name) {
var modName, ext, temp,
strip = false,
index = name.indexOf("."),
isRelative = name.indexOf('./') === 0 ||
name.indexOf('../') === 0;
if (index !== -1 && (!isRelative || index > 1)) {
modName = name.substring(0, index);
ext = name.substring(index + 1, name.length);
} else {
modName = name;
}
temp = ext || modName;
index = temp.indexOf("!");
if (index !== -1) {
//Pull off the strip arg.
strip = temp.substring(index + 1) === "strip";
temp = temp.substring(0, index);
if (ext) {
ext = temp;
} else {
modName = temp;
}
}
return {
moduleName: modName,
ext: ext,
strip: strip
};
},
xdRegExp: /^((\w+)\:)?\/\/([^\/\\]+)/,
/**
* Is an URL on another domain. Only works for browser use, returns
* false in non-browser environments. Only used to know if an
* optimized .js version of a text resource should be loaded
* instead.
* @param {String} url
* @returns Boolean
*/
useXhr: function (url, protocol, hostname, port) {
var uProtocol, uHostName, uPort,
match = text.xdRegExp.exec(url);
if (!match) {
return true;
}
uProtocol = match[2];
uHostName = match[3];
uHostName = uHostName.split(':');
uPort = uHostName[1];
uHostName = uHostName[0];
return (!uProtocol || uProtocol === protocol) &&
(!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) &&
((!uPort && !uHostName) || uPort === port);
},
finishLoad: function (name, strip, content, onLoad) {
content = strip ? text.strip(content) : content;
if (masterConfig.isBuild) {
buildMap[name] = content;
}
onLoad(content);
},
load: function (name, req, onLoad, config) {
//Name has format: some.module.filext!strip
//The strip part is optional.
//if strip is present, then that means only get the string contents
//inside a body tag in an HTML string. For XML/SVG content it means
//removing the <?xml ...?> declarations so the content can be inserted
//into the current doc without problems.
// Do not bother with the work if a build and text will
// not be inlined.
if (config && config.isBuild && !config.inlineText) {
onLoad();
return;
}
masterConfig.isBuild = config && config.isBuild;
var parsed = text.parseName(name),
nonStripName = parsed.moduleName +
(parsed.ext ? '.' + parsed.ext : ''),
url = req.toUrl(nonStripName),
useXhr = (masterConfig.useXhr) ||
text.useXhr;
// Do not load if it is an empty: url
if (url.indexOf('empty:') === 0) {
onLoad();
return;
}
//Load the text. Use XHR if possible and in a browser.
if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) {
text.get(url, function (content) {
text.finishLoad(name, parsed.strip, content, onLoad);
}, function (err) {
if (onLoad.error) {
onLoad.error(err);
}
});
} else {
//Need to fetch the resource across domains. Assume
//the resource has been optimized into a JS module. Fetch
//by the module name + extension, but do not include the
//!strip part to avoid file system issues.
req([nonStripName], function (content) {
text.finishLoad(parsed.moduleName + '.' + parsed.ext,
parsed.strip, content, onLoad);
});
}
},
write: function (pluginName, moduleName, write, config) {
if (buildMap.hasOwnProperty(moduleName)) {
var content = text.jsEscape(buildMap[moduleName]);
write.asModule(pluginName + "!" + moduleName,
"define(function () { return '" +
content +
"';});\n");
}
},
writeFile: function (pluginName, moduleName, req, write, config) {
var parsed = text.parseName(moduleName),
extPart = parsed.ext ? '.' + parsed.ext : '',
nonStripName = parsed.moduleName + extPart,
//Use a '.js' file name so that it indicates it is a
//script that can be loaded across domains.
fileName = req.toUrl(parsed.moduleName + extPart) + '.js';
//Leverage own load() method to load plugin value, but only
//write out values that do not have the strip argument,
//to avoid any potential issues with ! in file names.
text.load(nonStripName, req, function (value) {
//Use own write() method to construct full module value.
//But need to create shell that translates writeFile's
//write() to the right interface.
var textWrite = function (contents) {
return write(fileName, contents);
};
textWrite.asModule = function (moduleName, contents) {
return write.asModule(moduleName, fileName, contents);
};
text.write(pluginName, nonStripName, textWrite, config);
}, config);
}
};
if (masterConfig.env === 'node' || (!masterConfig.env &&
typeof process !== "undefined" &&
process.versions &&
!!process.versions.node &&
!process.versions['node-webkit'])) {
//Using special require.nodeRequire, something added by r.js.
fs = require.nodeRequire('fs');
text.get = function (url, callback, errback) {
try {
var file = fs.readFileSync(url, 'utf8');
//Remove BOM (Byte Mark Order) from utf8 files if it is there.
if (file.indexOf('\uFEFF') === 0) {
file = file.substring(1);
}
callback(file);
} catch (e) {
if (errback) {
errback(e);
}
}
};
} else if (masterConfig.env === 'xhr' || (!masterConfig.env &&
text.createXhr())) {
text.get = function (url, callback, errback, headers) {
var xhr = text.createXhr(), header;
xhr.open('GET', url, true);
//Allow plugins direct access to xhr headers
if (headers) {
for (header in headers) {
if (headers.hasOwnProperty(header)) {
xhr.setRequestHeader(header.toLowerCase(), headers[header]);
}
}
}
//Allow overrides specified in config
if (masterConfig.onXhr) {
masterConfig.onXhr(xhr, url);
}
xhr.onreadystatechange = function (evt) {
var status, err;
//Do not explicitly handle errors, those should be
//visible via console output in the browser.
if (xhr.readyState === 4) {
status = xhr.status || 0;
if (status > 399 && status < 600) {
//An http 4xx or 5xx error. Signal an error.
err = new Error(url + ' HTTP status: ' + status);
err.xhr = xhr;
if (errback) {
errback(err);
}
} else {
callback(xhr.responseText);
}
if (masterConfig.onXhrComplete) {
masterConfig.onXhrComplete(xhr, url);
}
}
};
xhr.send(null);
};
} else if (masterConfig.env === 'rhino' || (!masterConfig.env &&
typeof Packages !== 'undefined' && typeof java !== 'undefined')) {
//Why Java, why is this so awkward?
text.get = function (url, callback) {
var stringBuffer, line,
encoding = "utf-8",
file = new java.io.File(url),
lineSeparator = java.lang.System.getProperty("line.separator"),
input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),
content = '';
try {
stringBuffer = new java.lang.StringBuffer();
line = input.readLine();
// Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324
// http://www.unicode.org/faq/utf_bom.html
// Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK:
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058
if (line && line.length() && line.charAt(0) === 0xfeff) {
// Eat the BOM, since we've already found the encoding on this file,
// and we plan to concatenating this buffer with others; the BOM should
// only appear at the top of a file.
line = line.substring(1);
}
if (line !== null) {
stringBuffer.append(line);
}
while ((line = input.readLine()) !== null) {
stringBuffer.append(lineSeparator);
stringBuffer.append(line);
}
//Make sure we return a JavaScript string and not a Java string.
content = String(stringBuffer.toString()); //String
} finally {
input.close();
}
callback(content);
};
} else if (masterConfig.env === 'xpconnect' || (!masterConfig.env &&
typeof Components !== 'undefined' && Components.classes &&
Components.interfaces)) {
//Avert your gaze!
Cc = Components.classes;
Ci = Components.interfaces;
Components.utils['import']('resource://gre/modules/FileUtils.jsm');
xpcIsWindows = ('@mozilla.org/windows-registry-key;1' in Cc);
text.get = function (url, callback) {
var inStream, convertStream, fileObj,
readData = {};
if (xpcIsWindows) {
url = url.replace(/\//g, '\\');
}
fileObj = new FileUtils.File(url);
//XPCOM, you so crazy
try {
inStream = Cc['@mozilla.org/network/file-input-stream;1']
.createInstance(Ci.nsIFileInputStream);
inStream.init(fileObj, 1, 0, false);
convertStream = Cc['@mozilla.org/intl/converter-input-stream;1']
.createInstance(Ci.nsIConverterInputStream);
convertStream.init(inStream, "utf-8", inStream.available(),
Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
convertStream.readString(inStream.available(), readData);
convertStream.close();
inStream.close();
callback(readData.value);
} catch (e) {
throw new Error((fileObj && fileObj.path || '') + ': ' + e);
}
};
}
return text;
});

96
sitemap.xml

@ -0,0 +1,96 @@ @@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://pages.charlesreid1.com/github-heroku-attack-rabbits/</loc>
<lastmod>2018-06-17</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>https://pages.charlesreid1.com/github-heroku-attack-rabbits/heroku/</loc>
<lastmod>2018-06-17</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>https://pages.charlesreid1.com/github-heroku-attack-rabbits/github/</loc>
<lastmod>2018-06-17</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>https://pages.charlesreid1.com/github-heroku-attack-rabbits/repo/</loc>
<lastmod>2018-06-17</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>https://pages.charlesreid1.com/github-heroku-attack-rabbits/flask/</loc>
<lastmod>2018-06-17</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>https://pages.charlesreid1.com/github-heroku-attack-rabbits/flask_auth_github/</loc>
<lastmod>2018-06-17</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>https://pages.charlesreid1.com/github-heroku-attack-rabbits/flask_auth_org/</loc>
<lastmod>2018-06-17</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>https://pages.charlesreid1.com/github-heroku-attack-rabbits/flask_auth_other/</loc>
<lastmod>2018-06-17</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>https://pages.charlesreid1.com/github-heroku-attack-rabbits/flask_auth_portions/</loc>
<lastmod>2018-06-17</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>https://pages.charlesreid1.com/github-heroku-attack-rabbits/flask_local/</loc>
<lastmod>2018-06-17</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>https://pages.charlesreid1.com/github-heroku-attack-rabbits/flask_heroku/</loc>
<lastmod>2018-06-17</lastmod>
<changefreq>daily</changefreq>
</url>
<url>
<loc>https://pages.charlesreid1.com/github-heroku-attack-rabbits/custom_domains/</loc>
<lastmod>2018-06-17</lastmod>
<changefreq>daily</changefreq>
</url>
</urlset>
Loading…
Cancel
Save