Skip to content

Instantly share code, notes, and snippets.

Created March 16, 2018 17:05
Show Gist options
  • Select an option

  • Save anonymous/eae594db30c780fa8d2c25fa5b1962ce to your computer and use it in GitHub Desktop.

Select an option

Save anonymous/eae594db30c780fa8d2c25fa5b1962ce to your computer and use it in GitHub Desktop.

Revisions

  1. @invalid-email-address Anonymous created this gist Mar 16, 2018.
    47 changes: 47 additions & 0 deletions fiddle.css
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,47 @@
    label, button {
    display: block;
    margin-top: 8px;
    }
    body > fieldset {
    float: left;
    min-width: 250px;
    margin: 10px;
    }

    fieldset.collapsible {
    overflow: hidden;
    position: relative;
    border: none;
    padding-left: 0;
    padding-right: 0;
    margin: 0;
    }

    fieldset.collapsible legend {
    text-align: right;
    position: absolute;
    bottom: 0px;
    right: 20px;
    }

    fieldset.collapsible legend a:after {
    content: "+";
    }

    pre {
    padding: 10px;
    font-size: 16px;
    border-radius: 15px;
    background-color: #fafafa;
    border: 1px solid #999;
    max-width: 95%;
    word-wrap: break-word;
    white-space: pre-wrap;
    word-break: break-all;
    }
    br {
    clear: both;
    }
    .error {
    color: red;
    }
    46 changes: 46 additions & 0 deletions fiddle.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,46 @@
    <h2>Token Generator</h2>

    <p>Create Firebase tokens for use in testing, REST URLs, or just for admiring their beauty. Test them against your Firebase instance.</p>
    <fieldset>
    <legend>Create a Token</legend>
    <form id="createToken">
    <label for="secret">secret:</label>
    <input type="text" id="secret" />
    <label for="uid">uid:</label>
    <input type="text" id="uid" value="kato" />
    <label for="data">json data:</label>
    <textarea id="data" cols=50 rows=6></textarea>
    <fieldset class="collapsible active">
    <legend><a href="#">more options</a></legend>
    <label for="expires">expires:</label>
    <input type="text" id="expires" value="+30 days" placeholder="+30 days" /> <a href="#max">max</a>
    <label for="notBefore">notBefore:</label>
    <input type="text" id="notBefore" value="" placeholder="+0 minutes" />
    <label><input id="admin" type="checkbox" /> admin</label>
    <label><input id="debug" type="checkbox" /> debug</label>
    </fieldset>
    <button type="submit">create token</button>
    </form>
    </fieldset>
    <fieldset>
    <legend>Read/try a Token</legend>
    <form id="testToken">
    <label>https://
    <input type="text" id="instance" placeholder="instance" />.firebaseio.com</label>
    <label for="token">token:</label>
    <textarea id="token" cols=50 rows=6></textarea>
    <button type="submit">test token</button>
    </form>
    </fieldset>
    <br />
    <pre id="log"></pre>

    <br />
    <div>You can put any value into the json data you want and it will appear as part of the auth variable in security. The following administrative options are submitted as a second argument (try clicking "more options" and adding one):
    <ul>
    <li><strong>expires</strong>: A timestamp (as number of seconds since epoch) denoting the time after which this token should no longer be valid. There is no way to create a token that never expires, but try the "max" link to achieve something close enough.</li>
    <li><strong>notBefore</strong>: A timestamp (as number of seconds since epoch) denoting the time before which this token should be rejected by the server.</li>
    <li><strong>admin</strong>: Set to true if you want to disable all security rules for this client.</li>
    <li><strong>debug</strong>: Set to true to enable debug output from your Security Rules.</li>
    </ul>
    </div>
    174 changes: 174 additions & 0 deletions fiddle.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,174 @@
    $('#createToken').on('submit', createToken);
    $('#testToken').on('submit', testToken);
    $('#data').on('keyup change', validateJson);
    $('#uid').on('keyup change', setJsonId);

    $('#createToken')
    .on('submit', createToken)
    .find('input,textarea')
    .on('keyup change', setCreateButton)
    .on('keyup change', logCreateFormat);
    $('#testToken')
    .on('submit', testToken)
    .find('input,textarea')
    .on('keyup change', setTestButton);

    $('fieldset.collapsible legend a').click(function(e) {
    e.preventDefault();
    toggleMoreInfo($(this).closest('fieldset'));
    });

    $('a[href="#max"]').click(function(e) {
    e.preventDefault();
    $('#expires').val('+9999999 days');
    });

    toggleMoreInfo($('fieldset.collapsible'));
    setCreateButton();
    setTestButton();
    setJsonId();
    logCreateFormat();

    function setCreateButton() {
    var b = !$('#secret').val();
    $('#createToken').find('button').prop('disabled', b);
    }

    function setTestButton() {
    var b = !$('#instance').val() || !$('#token').val();
    $('#testToken').find('button').prop('disabled', b);
    }

    function setJsonId() {
    var uid = $('#uid').val();
    var out = $('#data').val();
    try {
    var json = JSON.parse(out || '{}');
    json.uid = uid;
    out = JSON.stringify(json, null, 2);
    } catch (e) {
    logErr(e);
    }
    $('#data').val(out);
    }

    function validateJson() {
    log('');
    var data = parseData();
    if( data !== false ) {
    logCreateFormat();
    }
    }

    function createToken(e) {
    e.preventDefault();
    var secret = $('#secret').val();
    var data = parseData();
    if( data !== false ) {
    var props = getAdminProps();
    var tokGen = new FirebaseTokenGenerator(secret);
    var token = tokGen.createToken(data, props);
    log(token);
    $('#token').val(token);
    selectLog();
    }
    return false;
    }

    function getAdminProps() {
    var exp = parseDate($('#expires').val());
    var notBefore = parseDate($('#notBefore').val());
    var admin = $('#admin').prop('checked');
    var debug = $('#debug').prop('checked');
    var out = {};
    out.expires = exp||0;
    if( notBefore ) out.notBefore = notBefore;
    if( admin ) out.admin = admin;
    if( debug ) out.debug = debug;
    return out;
    }

    function logCreateFormat() {
    var secret = $('#secret').val();
    var data = parseData();
    if( data === false ) return;
    log("new FirebaseTokenGenerator("
    +(secret? "'"+secret+"'" : '<ENTER SECRET>')
    +")\n.createToken("
    + JSON.stringify(parseData()||{}, null, 2)
    + ", "
    + JSON.stringify(getAdminProps(), null, 2)
    + ')');
    }

    function parseData() {
    try {
    return JSON.parse($('#data').val() || '{}');
    }
    catch(e) {
    logErr(e);
    return false;
    }
    }

    function testToken(e) {
    e.preventDefault();
    log('');
    var fb = new Firebase('https://' + $('#instance').val() + '.firebaseio.com');
    var tok = $('#token').val();
    var dat = decodeURIComponent(escape(window.atob(tok.split('.')[1])));
    fb.auth(tok, function (err) {
    if (err) {
    logErr(err + "\n\n" + dat);
    } else {
    log("Authenticated!\n\n" + dat);
    }
    });
    return false;
    }

    function log(txt) {
    $('pre').removeClass('error').text(txt);
    }

    function logErr(e) {
    $('pre').addClass('error').text(e);
    }

    function parseDate(v) {
    if( !v || v === '0' ) { return 0; }
    var m, matches = (v || '').match(/^([+-])(\d+) (\w+)$/);
    if (matches) {
    m = moment().add((matches[1] === '-'? -1 : 1)*parseInt(matches[2], 10), matches[3]);
    } else {
    m = moment(v);
    }
    return m.isValid() ? m.unix() : 0;
    }

    function selectLog() {
    function selectElementContents(el) {
    var range = document.createRange();
    range.selectNodeContents(el);
    var sel = window.getSelection();
    sel.removeAllRanges();
    sel.addRange(range);
    }

    var el = document.getElementById("log");
    selectElementContents(el);
    }

    function toggleMoreInfo($fs) {
    if( !$fs.data('origHeight') ) {
    $fs.data('origHeight', $fs.height());
    $fs.data('minHeight', $fs.find('label').outerHeight() + $fs.find('input').outerHeight()+5);
    }
    $fs.toggleClass('active');
    var h = $fs.data($fs.hasClass('active')? 'origHeight' : 'minHeight');
    $fs.animate({height: h});
    }