Server IP : 213.176.29.180  /  Your IP : 18.222.162.161
Web Server : Apache
System : Linux 213.176.29.180.hostiran.name 4.18.0-553.22.1.el8_10.x86_64 #1 SMP Tue Sep 24 05:16:59 EDT 2024 x86_64
User : webtaragh ( 1001)
PHP Version : 7.4.33
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON
Directory (0750) :  /home/webtaragh/public_html/wp-includes/theme-compat/../../

[  Home  ][  C0mmand  ][  Upload File  ]

Current File : /home/webtaragh/public_html/wp-includes/theme-compat/../../duosecurity.tar
duo_php/src/Web.php000064400000006250147361031610010224 0ustar00<?php
namespace Duo;

/*
 * https://duo.com/docs/duoweb
 */

class Web
{

    const DUO_PREFIX = "TX";
    const APP_PREFIX = "APP";
    const AUTH_PREFIX = "AUTH";

    const DUO_EXPIRE = 300;
    const APP_EXPIRE = 3600;

    const IKEY_LEN = 20;
    const SKEY_LEN = 40;
    const AKEY_LEN = 40; // if this changes you have to change ERR_AKEY

    const ERR_USER = 'ERR|The username specified is invalid.';
    const ERR_IKEY = 'ERR|The Duo integration key specified is invalid.';
    const ERR_SKEY = 'ERR|The Duo secret key specified is invalid.';
    const ERR_AKEY = 'ERR|The application secret key specified must be at least 40 characters.';

    private static function signVals($key, $vals, $prefix, $expire, $time = null)
    {
        $exp = ($time ? $time : time()) + $expire;
        $val = $vals . '|' . $exp;
        $b64 = base64_encode($val);
        $cookie = $prefix . '|' . $b64;

        $sig = hash_hmac("sha1", $cookie, $key);
        return $cookie . '|' . $sig;
    }

    private static function parseVals($key, $val, $prefix, $ikey, $time = null)
    {
        $ts = ($time ? $time : time());

        $parts = explode('|', $val);
        if (count($parts) !== 3) {
            return null;
        }
        list($u_prefix, $u_b64, $u_sig) = $parts;

        $sig = hash_hmac("sha1", $u_prefix . '|' . $u_b64, $key);
        if (hash_hmac("sha1", $sig, $key) !== hash_hmac("sha1", $u_sig, $key)) {
            return null;
        }

        if ($u_prefix !== $prefix) {
            return null;
        }

        $cookie_parts = explode('|', base64_decode($u_b64));
        if (count($cookie_parts) !== 3) {
            return null;
        }
        list($user, $u_ikey, $exp) = $cookie_parts;

        if ($u_ikey !== $ikey) {
            return null;
        }
        if ($ts >= intval($exp)) {
            return null;
        }

        return $user;
    }

    public static function signRequest($ikey, $skey, $akey, $username, $time = null)
    {
        if (!isset($username) || strlen($username) === 0) {
            return self::ERR_USER;
        }
        if (strpos($username, '|') !== false) {
            return self::ERR_USER;
        }
        if (!isset($ikey) || strlen($ikey) !== self::IKEY_LEN) {
            return self::ERR_IKEY;
        }
        if (!isset($skey) || strlen($skey) !== self::SKEY_LEN) {
            return self::ERR_SKEY;
        }
        if (!isset($akey) || strlen($akey) < self::AKEY_LEN) {
            return self::ERR_AKEY;
        }

        $vals = $username . '|' . $ikey;

        $duo_sig = self::signVals($skey, $vals, self::DUO_PREFIX, self::DUO_EXPIRE, $time);
        $app_sig = self::signVals($akey, $vals, self::APP_PREFIX, self::APP_EXPIRE, $time);

        return $duo_sig . ':' . $app_sig;
    }

    public static function verifyResponse($ikey, $skey, $akey, $sig_response, $time = null)
    {
        list($auth_sig, $app_sig) = explode(':', $sig_response);

        $auth_user = self::parseVals($skey, $auth_sig, self::AUTH_PREFIX, $ikey, $time);
        $app_user = self::parseVals($akey, $app_sig, self::APP_PREFIX, $ikey, $time);

        if ($auth_user !== $app_user) {
            return null;
        }

        return $auth_user;
    }
}
duo_php/README.md000064400000003244147361031610007466 0ustar00# Overview

[![Build Status](https://travis-ci.org/duosecurity/duo_php.svg?branch=master)](https://travis-ci.org/duosecurity/duo_php)

**duo_php** - Duo two-factor authentication for PHP web applications: https://duo.com/docs/duoweb

This package allows a web developer to quickly add Duo's interactive, self-service, two-factor authentication to any web login form - without setting up secondary user accounts, directory synchronization, servers, or hardware.

Files located in the `js` directory should be hosted by your webserver for inclusion in web pages.

# Installing

Development:

```
$ git clone https://github.com/duosecurity/duo_php.git
$ cd duo_php
$ composer install
```

System:

```
$ composer global require duosecurity/duo_php:dev-master
```

Or add the following to your project:

```
{
    "require": {
        "duosecurity/duo_php": "dev-master"
    }
}
```

# Using

```
$ php -a -d auto_prepend_file=vendor/autoload.php
Interactive mode enabled

php > var_dump(Duo\Web::signRequest($ikey, $skey, $akey, $username));
string(202) "TX|...TX_SIGNATURE...==|...TX_HASH...:APP|...APP_SIGNATURE...==|...APP_HASH..."
```

# Demo

First add an IKEY, SKEY, and HOST to `demos/simple/index.php`, and then run the following:

```
$ php -S localhost:8080 -t demos/simple/
```

# Test

```
$ ./vendor/bin/phpunit -c phpunit.xml
PHPUnit 5.3.2 by Sebastian Bergmann and contributors.

.............                                                     13 / 13 (100%)

Time: 62 ms, Memory: 6.00Mb

OK (13 tests, 13 assertions)
```

# Lint

```
$ ./vendor/bin/phpcs --standard=PSR2 -n src/* tests/*
```

# Support

Report any bugs, feature requests, etc. to us directly: support@duosecurity.com

duo_php/LICENSE000064400000002567147361031610007223 0ustar00Copyright (c) 2011, Duo Security, Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
   derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
duo_php/js/Duo-Web-v2.js000064400000046705147361031610010761 0ustar00/**
 * Duo Web SDK v2
 * Copyright 2019, Duo Security
 */

(function (root, factory) {
    /*eslint-disable */
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define([], factory);
    /*eslint-enable */
    } else if (typeof module === 'object' && module.exports) {
        // Node. Does not work with strict CommonJS, but
        // only CommonJS-like environments that support module.exports,
        // like Node.
        module.exports = factory();
    } else {
        // Browser globals (root is window)
        var Duo = factory();
        // If the Javascript was loaded via a script tag, attempt to autoload
        // the frame.
        Duo._onReady(Duo.init);

        // Attach Duo to the `window` object
        root.Duo = Duo;
  }
}(this, function() {
    var DUO_MESSAGE_FORMAT = /^(?:AUTH|ENROLL)+\|[A-Za-z0-9\+\/=]+\|[A-Za-z0-9\+\/=]+$/;
    var DUO_ERROR_FORMAT = /^ERR\|[\w\s\.\(\)]+$/;
    var DUO_OPEN_WINDOW_FORMAT = /^DUO_OPEN_WINDOW\|/;
    var VALID_OPEN_WINDOW_DOMAINS = [
        'duo.com',
        'duosecurity.com',
        'duomobile.s3-us-west-1.amazonaws.com'
    ];

    var postAction,
        postArgument,
        host,
        sigRequest,
        duoSig,
        appSig,
        iframe,
        submitCallback;

    // We use this function instead of setting initial values in the var
    // declarations to make sure the initial values and subsequent
    // re-initializations are always the same.
    initializeStatefulVariables();

    /**
     * Set local variables to whatever they should be before you call init().
     */
    function initializeStatefulVariables() {
        postAction = '';
        postArgument = 'sig_response';
        host = undefined;
        sigRequest = undefined;
        duoSig = undefined;
        appSig = undefined;
        iframe = undefined;
        submitCallback = undefined;
    }

    function throwError(message, givenUrl) {
        var url = (
            givenUrl ||
            'https://www.duosecurity.com/docs/duoweb#3.-show-the-iframe'
        );
        throw new Error(
            'Duo Web SDK error: ' + message +
            (url ? ('\n' + 'See ' + url + ' for more information') : '')
        );
    }

    function hyphenize(str) {
        return str.replace(/([a-z])([A-Z])/, '$1-$2').toLowerCase();
    }

    // cross-browser data attributes
    function getDataAttribute(element, name) {
        if ('dataset' in element) {
            return element.dataset[name];
        } else {
            return element.getAttribute('data-' + hyphenize(name));
        }
    }

    // cross-browser event binding/unbinding
    function on(context, event, fallbackEvent, callback) {
        if ('addEventListener' in window) {
            context.addEventListener(event, callback, false);
        } else {
            context.attachEvent(fallbackEvent, callback);
        }
    }

    function off(context, event, fallbackEvent, callback) {
        if ('removeEventListener' in window) {
            context.removeEventListener(event, callback, false);
        } else {
            context.detachEvent(fallbackEvent, callback);
        }
    }

    function onReady(callback) {
        on(document, 'DOMContentLoaded', 'onreadystatechange', callback);
    }

    function offReady(callback) {
        off(document, 'DOMContentLoaded', 'onreadystatechange', callback);
    }

    function onMessage(callback) {
        on(window, 'message', 'onmessage', callback);
    }

    function offMessage(callback) {
        off(window, 'message', 'onmessage', callback);
    }

    /**
     * Parse the sig_request parameter, throwing errors if the token contains
     * a server error or if the token is invalid.
     *
     * @param {String} sig Request token
     */
    function parseSigRequest(sig) {
        if (!sig) {
            // nothing to do
            return;
        }

        // see if the token contains an error, throwing it if it does
        if (sig.indexOf('ERR|') === 0) {
            throwError(sig.split('|')[1]);
        }

        // validate the token
        if (sig.indexOf(':') === -1 || sig.split(':').length !== 2) {
            throwError(
                'Duo was given a bad token.  This might indicate a configuration ' +
                'problem with one of Duo\'s client libraries.'
            );
        }

        var sigParts = sig.split(':');

        // hang on to the token, and the parsed duo and app sigs
        sigRequest = sig;
        duoSig = sigParts[0];
        appSig = sigParts[1];

        return {
            sigRequest: sig,
            duoSig: sigParts[0],
            appSig: sigParts[1]
        };
    }

    /**
     * Validate that a MessageEvent came from the Duo service, and that it
     * is a properly formatted payload.
     *
     * The Google Chrome sign-in page injects some JS into pages that also
     * make use of postMessage, so we need to do additional validation above
     * and beyond the origin.
     *
     * @param {MessageEvent} event Message received via postMessage
     */
    function isDuoMessage(event) {
        return Boolean(
            event.origin === ('https://' + host) &&
            typeof event.data === 'string' &&
            (
                event.data.match(DUO_MESSAGE_FORMAT) ||
                event.data.match(DUO_ERROR_FORMAT) ||
                event.data.match(DUO_OPEN_WINDOW_FORMAT)
            )
        );
    }

    /**
     * Validate the request token and prepare for the iframe to become ready.
     *
     * All options below can be passed into an options hash to `Duo.init`, or
     * specified on the iframe using `data-` attributes.
     *
     * Options specified using the options hash will take precedence over
     * `data-` attributes.
     *
     * Example using options hash:
     * ```javascript
     * Duo.init({
     *     iframe: "some_other_id",
     *     host: "api-main.duo.test",
     *     sig_request: "...",
     *     post_action: "/auth",
     *     post_argument: "resp"
     * });
     * ```
     *
     * Example using `data-` attributes:
     * ```html
     * <iframe id="duo_iframe"
     *         data-host="api-main.duo.test"
     *         data-sig-request="..."
     *         data-post-action="/auth"
     *         data-post-argument="resp"
     *         >
     * </iframe>
     * ```
     *
     * Some browsers (especially embedded browsers) don't like it when the Duo
     * Web SDK changes the `src` attribute on the iframe. To prevent this, there
     * is an alternative way to use the Duo Web SDK:
     *
     * Add a div (or any other container element) instead of an iframe to the
     * DOM with an id of "duo_iframe", or pass that element to the
     * `iframeContainer` parameter of `Duo.init`. An iframe will be created and
     * inserted into that container element, preventing `src` change related
     * bugs. WARNING: All other elements in the container will be deleted.
     *
     * The `iframeAttributes` parameter of `Duo.init` is available to set any
     * attributes on the inserted iframe if the Duo Web SDK is inserting the
     * iframe. For details, see the parameter documentation below.
     *
     * @param {Object} options
     * @param {String} options.host - Hostname for the Duo Prompt.
     * @param {String} options.sig_request - Request token.
     * @param {String|HTMLElement} [options.iframe] - The iframe, or id of an
     *     iframe that will be used for the Duo Prompt. If you don't provide
     *     this or the `iframeContainer` parameter the Duo Web SDK will default
     *     to using whatever element has an id of "duo_iframe".
     * @param {String|HTMLElement} [options.iframeContainer] - The element you
     *     want the Duo Prompt inserted into, or the id of that element.
     *     Anything inside this element will be deleted and replaced with an
     *     iframe hosting the Duo prompt. If you don't provide this or the
     *     `iframe` parameter the Duo Web SDK will default to using whatever
     *     element has an id of "duo_iframe".
     * @param {Object} [options.iframeAttributes] - Object with  names and
     *     values coresponding to attributes you want added to the  Duo Prompt
     *     iframe, like `title`, `width` and `allow`. WARNING: this parameter
     *     only works if you use the `iframeContainer` parameter or add an id
     *     of "duo_iframe" to an element that isn't an iframe. If you have
     *     added an iframe to the DOM yourself, you should set those attributes
     *     directly on the iframe.
     * @param {String} [options.post_action=''] - URL to POST back to after a
     *     successful auth.
     * @param {String} [options.post_argument='sig_response'] - Parameter name
     *     to use for response token.
     * @param {Function} [options.submit_callback] - If provided, the Duo Web
     *     SDK will not submit the form. Instead it will execute this callback
     *     function passing in a reference to the "duo_form" form object.
     *     `submit_callback`` can be used to prevent the webpage from reloading.
     */
    function init(options) {
        // If init() is called more than once we have to reset all the local
        // variables to ensure init() will work the same way every time. This
        // helps people making single page applications. SPAs may periodically
        // remove the iframe and add a new one that has to be initialized.
        initializeStatefulVariables();

        if (options) {
            if (options.host) {
                host = options.host;
            }

            if (options.sig_request) {
                parseSigRequest(options.sig_request);
            }

            if (options.post_action) {
                postAction = options.post_action;
            }

            if (options.post_argument) {
                postArgument = options.post_argument;
            }

            if (typeof options.submit_callback === 'function') {
                submitCallback = options.submit_callback;
            }
        }

        var promptElement = getPromptElement(options);
        if (promptElement) {
            // If we can get the element that will host the prompt, set it.
            ready(promptElement, options.iframeAttributes || {});
        } else {
            // If the element that will host the prompt isn't available yet, set
            // it up after the DOM finishes loading.
            asyncReady(options);
        }

        // always clean up after yourself!
        offReady(init);
    }

    /**
     * Given the options from init(), get the iframe or iframe container that
     * should be used for the Duo Prompt. Returns `null` if nothing was found.
     */
    function getPromptElement(options) {
        var result;

        if (options.iframe && options.iframeContainer) {
            throwError(
                'Passing both `iframe` and `iframeContainer` arguments at the' +
                ' same time is not allowed.'
            );
        } else if (options.iframe) {
            // If we are getting an iframe, try to get it and raise if the
            // element we find is NOT an iframe.
            result = getUserDefinedElement(options.iframe);
            validateIframe(result);
        } else if (options.iframeContainer) {
            result = getUserDefinedElement(options.iframeContainer);
            validateIframeContainer(result);
        } else {
            result = document.getElementById('duo_iframe');
        }

        return result;
    }

    /**
     * When given an HTMLElement, return it. When given a string, get an element
     * with that id, else return null.
     */
    function getUserDefinedElement(object) {
        if (object.tagName) {
            return object;
        } else if (typeof object == 'string') {
            return document.getElementById(object);
        }
        return null;
    }

    /**
     * Check if the given thing is an iframe.
     */
    function isIframe(element) {
        return (
            element &&
            element.tagName &&
            element.tagName.toLowerCase() === 'iframe'
        );
    }

    /**
     * Throw an error if we are given an element that is NOT an iframe.
     */
    function validateIframe(element) {
        if (element && !isIframe(element)) {
            throwError(
                '`iframe` only accepts an iframe element or the id of an' +
                ' iframe. To use a non-iframe element, use the' +
                ' `iframeContainer` argument.'
            );
        }
    }

    /**
     * Throw an error if we are given an element that IS an iframe instead of an
     * element that we can insert an iframe into.
     */
    function validateIframeContainer(element) {
        if (element && isIframe(element)) {
            throwError(
                '`iframeContainer` only accepts a non-iframe element or the' +
                ' id of a non-iframe. To use a non-iframe element, use the' +
                ' `iframeContainer` argument on Duo.init().'
            );
        }
    }

    /**
     * Generate the URL that goes to the Duo Prompt.
     */
    function generateIframeSrc() {
        return [
            'https://', host, '/frame/web/v1/auth?tx=', duoSig,
            '&parent=', encodeURIComponent(document.location.href),
            '&v=2.8'
        ].join('');
    }

    /**
     * This function is called when a message was received from another domain
     * using the `postMessage` API.  Check that the event came from the Duo
     * service domain, and that the message is a properly formatted payload,
     * then perform the post back to the primary service.
     *
     * @param event Event object (contains origin and data)
     */
    function onReceivedMessage(event) {
        if (isDuoMessage(event)) {
            if (event.data.match(DUO_OPEN_WINDOW_FORMAT)) {
                var url = event.data.substring("DUO_OPEN_WINDOW|".length);
                if (isValidUrlToOpen(url)) {
                    // Open the URL that comes after the DUO_WINDOW_OPEN token.
                    window.open(url, "_self");
                }
            }
            else {
                // the event came from duo, do the post back
                doPostBack(event.data);

                // always clean up after yourself!
                offMessage(onReceivedMessage);
            }
        }
    }

    /**
     * Validate that this passed in URL is one that we will actually allow to
     * be opened.
     * @param url String URL that the message poster wants to open
     * @returns {boolean} true if we allow this url to be opened in the window
     */
    function isValidUrlToOpen(url) {
        if (!url) {
            return false;
        }

        var parser = document.createElement('a');
        parser.href = url;

        if (parser.protocol === "duotrustedendpoints:") {
            return true;
        } else if (parser.protocol !== "https:") {
            return false;
        }

        for (var i = 0; i < VALID_OPEN_WINDOW_DOMAINS.length; i++) {
           if (parser.hostname.endsWith("." + VALID_OPEN_WINDOW_DOMAINS[i]) ||
                   parser.hostname === VALID_OPEN_WINDOW_DOMAINS[i]) {
               return true;
           }
        }
        return false;
    }

    /**
     * Register a callback to call ready() after the DOM has loaded.
     */
    function asyncReady(options) {
        var callback = function() {
            var promptElement = getPromptElement(options);
            if (!promptElement) {
                throwError(
                    'This page does not contain an iframe for Duo to use.' +
                    ' Add an element like' +
                    ' <iframe id="duo_iframe"></iframe> to this page.'
                );
            }

            ready(promptElement, options.iframeAttributes || {});

            // Always clean up after yourself.
            offReady(callback)
        };

        onReady(callback);
    }

    /**
     * Point the iframe at Duo, then wait for it to postMessage back to us.
     */
    function ready(promptElement, iframeAttributes) {
        if (!host) {
            host = getDataAttribute(promptElement, 'host');

            if (!host) {
                throwError(
                    'No API hostname is given for Duo to use.  Be sure to pass ' +
                    'a `host` parameter to Duo.init, or through the `data-host` ' +
                    'attribute on the iframe element.'
                );
            }
        }

        if (!duoSig || !appSig) {
            parseSigRequest(getDataAttribute(promptElement, 'sigRequest'));

            if (!duoSig || !appSig) {
                throwError(
                    'No valid signed request is given.  Be sure to give the ' +
                    '`sig_request` parameter to Duo.init, or use the ' +
                    '`data-sig-request` attribute on the iframe element.'
                );
            }
        }

        // if postAction/Argument are defaults, see if they are specified
        // as data attributes on the iframe
        if (postAction === '') {
            postAction = getDataAttribute(promptElement, 'postAction') || postAction;
        }

        if (postArgument === 'sig_response') {
            postArgument = getDataAttribute(promptElement, 'postArgument') || postArgument;
        }

        if (isIframe(promptElement)) {
            iframe = promptElement;
            iframe.src = generateIframeSrc();
        } else {
            // If given a container to put an iframe in, clean out any children
            // child elements in case `init()` was called more than once.
            while (promptElement.firstChild) {
                // We call `removeChild()` instead of doing `innerHTML = ""`
                // to make sure we unbind any events.
                promptElement.removeChild(promptElement.firstChild)
            }

            iframe = document.createElement('iframe');

            // Set the src and all other attributes on the new iframe.
            iframeAttributes['src'] = generateIframeSrc();
            for (var name in iframeAttributes) {
                iframe.setAttribute(name, iframeAttributes[name]);
            }

            promptElement.appendChild(iframe);
        }

        // listen for the 'message' event
        onMessage(onReceivedMessage);
    }

    /**
     * We received a postMessage from Duo.  POST back to the primary service
     * with the response token, and any additional user-supplied parameters
     * given in form#duo_form.
     */
    function doPostBack(response) {
        // create a hidden input to contain the response token
        var input = document.createElement('input');
        input.type = 'hidden';
        input.name = postArgument;
        input.value = response + ':' + appSig;

        // user may supply their own form with additional inputs
        var form = document.getElementById('duo_form');

        // if the form doesn't exist, create one
        if (!form) {
            form = document.createElement('form');

            // insert the new form after the iframe
            iframe.parentElement.insertBefore(form, iframe.nextSibling);
        }

        // make sure we are actually posting to the right place
        form.method = 'POST';
        form.action = postAction;

        // add the response token input to the form
        form.appendChild(input);

        // away we go!
        if (typeof submitCallback === "function") {
            submitCallback.call(null, form);
        } else {
            form.submit();
        }
    }

    return {
        init: init,
        _onReady: onReady,
        _parseSigRequest: parseSigRequest,
        _isDuoMessage: isDuoMessage,
        _doPostBack: doPostBack
    };
}));
duo_php/js/Duo-Web-v2.min.js000064400000010552147361031610011532 0ustar00!function(e,t){if("function"==typeof define&&define.amd)define([],t);else if("object"==typeof module&&module.exports)module.exports=t();else{var n=t();n._onReady(n.init),e.Duo=n}}(this,function(){var i,a,r,s,u,f,m,t=/^(?:AUTH|ENROLL)+\|[A-Za-z0-9\+\/=]+\|[A-Za-z0-9\+\/=]+$/,n=/^ERR\|[\w\s\.\(\)]+$/,d=/^DUO_OPEN_WINDOW\|/,c=["duo.com","duosecurity.com","duomobile.s3-us-west-1.amazonaws.com"];function l(){i="",a="sig_response",r=undefined,undefined,s=undefined,u=undefined,f=undefined,m=undefined}function h(e,t){var n=t||"https://www.duosecurity.com/docs/duoweb#3.-show-the-iframe";throw new Error("Duo Web SDK error: "+e+(n?"\nSee "+n+" for more information":""))}function g(e,t){return"dataset"in e?e.dataset[t]:e.getAttribute("data-"+function n(e){return e.replace(/([a-z])([A-Z])/,"$1-$2").toLowerCase()}(t))}function p(e,t,n,o){"addEventListener"in window?e.addEventListener(t,o,!1):e.attachEvent(n,o)}function v(e,t,n,o){"removeEventListener"in window?e.removeEventListener(t,o,!1):e.detachEvent(n,o)}function w(e){p(document,"DOMContentLoaded","onreadystatechange",e)}function _(e){v(document,"DOMContentLoaded","onreadystatechange",e)}function b(e){if(e){0===e.indexOf("ERR|")&&h(e.split("|")[1]),-1!==e.indexOf(":")&&2===e.split(":").length||h("Duo was given a bad token.  This might indicate a configuration problem with one of Duo's client libraries.");var t=e.split(":");return e,s=t[0],u=t[1],{sigRequest:e,duoSig:t[0],appSig:t[1]}}}function E(e){return Boolean(e.origin==="https://"+r&&"string"==typeof e.data&&(e.data.match(t)||e.data.match(n)||e.data.match(d)))}function y(e){var t;return e.iframe&&e.iframeContainer?h("Passing both `iframe` and `iframeContainer` arguments at the same time is not allowed."):e.iframe?function n(e){e&&!D(e)&&h("`iframe` only accepts an iframe element or the id of an iframe. To use a non-iframe element, use the `iframeContainer` argument.")}(t=C(e.iframe)):e.iframeContainer?function o(e){e&&D(e)&&h("`iframeContainer` only accepts a non-iframe element or the id of a non-iframe. To use a non-iframe element, use the `iframeContainer` argument on Duo.init().")}(t=C(e.iframeContainer)):t=document.getElementById("duo_iframe"),t}function C(e){return e.tagName?e:"string"==typeof e?document.getElementById(e):null}function D(e){return e&&e.tagName&&"iframe"===e.tagName.toLowerCase()}function A(){return["https://",r,"/frame/web/v1/auth?tx=",s,"&parent=",encodeURIComponent(document.location.href),"&v=2.8"].join("")}function O(e){if(E(e))if(e.data.match(d)){var t=e.data.substring("DUO_OPEN_WINDOW|".length);(function o(e){if(!e)return!1;var t=document.createElement("a");{if(t.href=e,"duotrustedendpoints:"===t.protocol)return!0;if("https:"!==t.protocol)return!1}for(var n=0;n<c.length;n++)if(t.hostname.endsWith("."+c[n])||t.hostname===c[n])return!0;return!1})(t)&&window.open(t,"_self")}else L(e.data),function n(e){v(window,"message","onmessage",e)}(O)}function R(e,t){if(r||(r=g(e,"host"))||h("No API hostname is given for Duo to use.  Be sure to pass a `host` parameter to Duo.init, or through the `data-host` attribute on the iframe element."),s&&u||(b(g(e,"sigRequest")),s&&u||h("No valid signed request is given.  Be sure to give the `sig_request` parameter to Duo.init, or use the `data-sig-request` attribute on the iframe element.")),""===i&&(i=g(e,"postAction")||i),"sig_response"===a&&(a=g(e,"postArgument")||a),D(e))(f=e).src=A();else{for(;e.firstChild;)e.removeChild(e.firstChild);for(var n in f=document.createElement("iframe"),t.src=A(),t)f.setAttribute(n,t[n]);e.appendChild(f)}!function o(e){p(window,"message","onmessage",e)}(O)}function L(e){var t=document.createElement("input");t.type="hidden",t.name=a,t.value=e+":"+u;var n=document.getElementById("duo_form");n||(n=document.createElement("form"),f.parentElement.insertBefore(n,f.nextSibling)),n.method="POST",n.action=i,n.appendChild(t),"function"==typeof m?m.call(null,n):n.submit()}return l(),{init:function N(e){l(),e&&(e.host&&(r=e.host),e.sig_request&&b(e.sig_request),e.post_action&&(i=e.post_action),e.post_argument&&(a=e.post_argument),"function"==typeof e.submit_callback&&(m=e.submit_callback));var t=y(e);t?R(t,e.iframeAttributes||{}):function o(t){var n=function(){var e=y(t);e||h('This page does not contain an iframe for Duo to use. Add an element like <iframe id="duo_iframe"></iframe> to this page.'),R(e,t.iframeAttributes||{}),_(n)};w(n)}(e),_(N)},_onReady:w,_parseSigRequest:b,_isDuoMessage:E,_doPostBack:L}});duo_php/demos/simple/Duo-Web-v2.js000064400000046705147361031610012745 0ustar00/**
 * Duo Web SDK v2
 * Copyright 2019, Duo Security
 */

(function (root, factory) {
    /*eslint-disable */
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define([], factory);
    /*eslint-enable */
    } else if (typeof module === 'object' && module.exports) {
        // Node. Does not work with strict CommonJS, but
        // only CommonJS-like environments that support module.exports,
        // like Node.
        module.exports = factory();
    } else {
        // Browser globals (root is window)
        var Duo = factory();
        // If the Javascript was loaded via a script tag, attempt to autoload
        // the frame.
        Duo._onReady(Duo.init);

        // Attach Duo to the `window` object
        root.Duo = Duo;
  }
}(this, function() {
    var DUO_MESSAGE_FORMAT = /^(?:AUTH|ENROLL)+\|[A-Za-z0-9\+\/=]+\|[A-Za-z0-9\+\/=]+$/;
    var DUO_ERROR_FORMAT = /^ERR\|[\w\s\.\(\)]+$/;
    var DUO_OPEN_WINDOW_FORMAT = /^DUO_OPEN_WINDOW\|/;
    var VALID_OPEN_WINDOW_DOMAINS = [
        'duo.com',
        'duosecurity.com',
        'duomobile.s3-us-west-1.amazonaws.com'
    ];

    var postAction,
        postArgument,
        host,
        sigRequest,
        duoSig,
        appSig,
        iframe,
        submitCallback;

    // We use this function instead of setting initial values in the var
    // declarations to make sure the initial values and subsequent
    // re-initializations are always the same.
    initializeStatefulVariables();

    /**
     * Set local variables to whatever they should be before you call init().
     */
    function initializeStatefulVariables() {
        postAction = '';
        postArgument = 'sig_response';
        host = undefined;
        sigRequest = undefined;
        duoSig = undefined;
        appSig = undefined;
        iframe = undefined;
        submitCallback = undefined;
    }

    function throwError(message, givenUrl) {
        var url = (
            givenUrl ||
            'https://www.duosecurity.com/docs/duoweb#3.-show-the-iframe'
        );
        throw new Error(
            'Duo Web SDK error: ' + message +
            (url ? ('\n' + 'See ' + url + ' for more information') : '')
        );
    }

    function hyphenize(str) {
        return str.replace(/([a-z])([A-Z])/, '$1-$2').toLowerCase();
    }

    // cross-browser data attributes
    function getDataAttribute(element, name) {
        if ('dataset' in element) {
            return element.dataset[name];
        } else {
            return element.getAttribute('data-' + hyphenize(name));
        }
    }

    // cross-browser event binding/unbinding
    function on(context, event, fallbackEvent, callback) {
        if ('addEventListener' in window) {
            context.addEventListener(event, callback, false);
        } else {
            context.attachEvent(fallbackEvent, callback);
        }
    }

    function off(context, event, fallbackEvent, callback) {
        if ('removeEventListener' in window) {
            context.removeEventListener(event, callback, false);
        } else {
            context.detachEvent(fallbackEvent, callback);
        }
    }

    function onReady(callback) {
        on(document, 'DOMContentLoaded', 'onreadystatechange', callback);
    }

    function offReady(callback) {
        off(document, 'DOMContentLoaded', 'onreadystatechange', callback);
    }

    function onMessage(callback) {
        on(window, 'message', 'onmessage', callback);
    }

    function offMessage(callback) {
        off(window, 'message', 'onmessage', callback);
    }

    /**
     * Parse the sig_request parameter, throwing errors if the token contains
     * a server error or if the token is invalid.
     *
     * @param {String} sig Request token
     */
    function parseSigRequest(sig) {
        if (!sig) {
            // nothing to do
            return;
        }

        // see if the token contains an error, throwing it if it does
        if (sig.indexOf('ERR|') === 0) {
            throwError(sig.split('|')[1]);
        }

        // validate the token
        if (sig.indexOf(':') === -1 || sig.split(':').length !== 2) {
            throwError(
                'Duo was given a bad token.  This might indicate a configuration ' +
                'problem with one of Duo\'s client libraries.'
            );
        }

        var sigParts = sig.split(':');

        // hang on to the token, and the parsed duo and app sigs
        sigRequest = sig;
        duoSig = sigParts[0];
        appSig = sigParts[1];

        return {
            sigRequest: sig,
            duoSig: sigParts[0],
            appSig: sigParts[1]
        };
    }

    /**
     * Validate that a MessageEvent came from the Duo service, and that it
     * is a properly formatted payload.
     *
     * The Google Chrome sign-in page injects some JS into pages that also
     * make use of postMessage, so we need to do additional validation above
     * and beyond the origin.
     *
     * @param {MessageEvent} event Message received via postMessage
     */
    function isDuoMessage(event) {
        return Boolean(
            event.origin === ('https://' + host) &&
            typeof event.data === 'string' &&
            (
                event.data.match(DUO_MESSAGE_FORMAT) ||
                event.data.match(DUO_ERROR_FORMAT) ||
                event.data.match(DUO_OPEN_WINDOW_FORMAT)
            )
        );
    }

    /**
     * Validate the request token and prepare for the iframe to become ready.
     *
     * All options below can be passed into an options hash to `Duo.init`, or
     * specified on the iframe using `data-` attributes.
     *
     * Options specified using the options hash will take precedence over
     * `data-` attributes.
     *
     * Example using options hash:
     * ```javascript
     * Duo.init({
     *     iframe: "some_other_id",
     *     host: "api-main.duo.test",
     *     sig_request: "...",
     *     post_action: "/auth",
     *     post_argument: "resp"
     * });
     * ```
     *
     * Example using `data-` attributes:
     * ```html
     * <iframe id="duo_iframe"
     *         data-host="api-main.duo.test"
     *         data-sig-request="..."
     *         data-post-action="/auth"
     *         data-post-argument="resp"
     *         >
     * </iframe>
     * ```
     *
     * Some browsers (especially embedded browsers) don't like it when the Duo
     * Web SDK changes the `src` attribute on the iframe. To prevent this, there
     * is an alternative way to use the Duo Web SDK:
     *
     * Add a div (or any other container element) instead of an iframe to the
     * DOM with an id of "duo_iframe", or pass that element to the
     * `iframeContainer` parameter of `Duo.init`. An iframe will be created and
     * inserted into that container element, preventing `src` change related
     * bugs. WARNING: All other elements in the container will be deleted.
     *
     * The `iframeAttributes` parameter of `Duo.init` is available to set any
     * attributes on the inserted iframe if the Duo Web SDK is inserting the
     * iframe. For details, see the parameter documentation below.
     *
     * @param {Object} options
     * @param {String} options.host - Hostname for the Duo Prompt.
     * @param {String} options.sig_request - Request token.
     * @param {String|HTMLElement} [options.iframe] - The iframe, or id of an
     *     iframe that will be used for the Duo Prompt. If you don't provide
     *     this or the `iframeContainer` parameter the Duo Web SDK will default
     *     to using whatever element has an id of "duo_iframe".
     * @param {String|HTMLElement} [options.iframeContainer] - The element you
     *     want the Duo Prompt inserted into, or the id of that element.
     *     Anything inside this element will be deleted and replaced with an
     *     iframe hosting the Duo prompt. If you don't provide this or the
     *     `iframe` parameter the Duo Web SDK will default to using whatever
     *     element has an id of "duo_iframe".
     * @param {Object} [options.iframeAttributes] - Object with  names and
     *     values coresponding to attributes you want added to the  Duo Prompt
     *     iframe, like `title`, `width` and `allow`. WARNING: this parameter
     *     only works if you use the `iframeContainer` parameter or add an id
     *     of "duo_iframe" to an element that isn't an iframe. If you have
     *     added an iframe to the DOM yourself, you should set those attributes
     *     directly on the iframe.
     * @param {String} [options.post_action=''] - URL to POST back to after a
     *     successful auth.
     * @param {String} [options.post_argument='sig_response'] - Parameter name
     *     to use for response token.
     * @param {Function} [options.submit_callback] - If provided, the Duo Web
     *     SDK will not submit the form. Instead it will execute this callback
     *     function passing in a reference to the "duo_form" form object.
     *     `submit_callback`` can be used to prevent the webpage from reloading.
     */
    function init(options) {
        // If init() is called more than once we have to reset all the local
        // variables to ensure init() will work the same way every time. This
        // helps people making single page applications. SPAs may periodically
        // remove the iframe and add a new one that has to be initialized.
        initializeStatefulVariables();

        if (options) {
            if (options.host) {
                host = options.host;
            }

            if (options.sig_request) {
                parseSigRequest(options.sig_request);
            }

            if (options.post_action) {
                postAction = options.post_action;
            }

            if (options.post_argument) {
                postArgument = options.post_argument;
            }

            if (typeof options.submit_callback === 'function') {
                submitCallback = options.submit_callback;
            }
        }

        var promptElement = getPromptElement(options);
        if (promptElement) {
            // If we can get the element that will host the prompt, set it.
            ready(promptElement, options.iframeAttributes || {});
        } else {
            // If the element that will host the prompt isn't available yet, set
            // it up after the DOM finishes loading.
            asyncReady(options);
        }

        // always clean up after yourself!
        offReady(init);
    }

    /**
     * Given the options from init(), get the iframe or iframe container that
     * should be used for the Duo Prompt. Returns `null` if nothing was found.
     */
    function getPromptElement(options) {
        var result;

        if (options.iframe && options.iframeContainer) {
            throwError(
                'Passing both `iframe` and `iframeContainer` arguments at the' +
                ' same time is not allowed.'
            );
        } else if (options.iframe) {
            // If we are getting an iframe, try to get it and raise if the
            // element we find is NOT an iframe.
            result = getUserDefinedElement(options.iframe);
            validateIframe(result);
        } else if (options.iframeContainer) {
            result = getUserDefinedElement(options.iframeContainer);
            validateIframeContainer(result);
        } else {
            result = document.getElementById('duo_iframe');
        }

        return result;
    }

    /**
     * When given an HTMLElement, return it. When given a string, get an element
     * with that id, else return null.
     */
    function getUserDefinedElement(object) {
        if (object.tagName) {
            return object;
        } else if (typeof object == 'string') {
            return document.getElementById(object);
        }
        return null;
    }

    /**
     * Check if the given thing is an iframe.
     */
    function isIframe(element) {
        return (
            element &&
            element.tagName &&
            element.tagName.toLowerCase() === 'iframe'
        );
    }

    /**
     * Throw an error if we are given an element that is NOT an iframe.
     */
    function validateIframe(element) {
        if (element && !isIframe(element)) {
            throwError(
                '`iframe` only accepts an iframe element or the id of an' +
                ' iframe. To use a non-iframe element, use the' +
                ' `iframeContainer` argument.'
            );
        }
    }

    /**
     * Throw an error if we are given an element that IS an iframe instead of an
     * element that we can insert an iframe into.
     */
    function validateIframeContainer(element) {
        if (element && isIframe(element)) {
            throwError(
                '`iframeContainer` only accepts a non-iframe element or the' +
                ' id of a non-iframe. To use a non-iframe element, use the' +
                ' `iframeContainer` argument on Duo.init().'
            );
        }
    }

    /**
     * Generate the URL that goes to the Duo Prompt.
     */
    function generateIframeSrc() {
        return [
            'https://', host, '/frame/web/v1/auth?tx=', duoSig,
            '&parent=', encodeURIComponent(document.location.href),
            '&v=2.8'
        ].join('');
    }

    /**
     * This function is called when a message was received from another domain
     * using the `postMessage` API.  Check that the event came from the Duo
     * service domain, and that the message is a properly formatted payload,
     * then perform the post back to the primary service.
     *
     * @param event Event object (contains origin and data)
     */
    function onReceivedMessage(event) {
        if (isDuoMessage(event)) {
            if (event.data.match(DUO_OPEN_WINDOW_FORMAT)) {
                var url = event.data.substring("DUO_OPEN_WINDOW|".length);
                if (isValidUrlToOpen(url)) {
                    // Open the URL that comes after the DUO_WINDOW_OPEN token.
                    window.open(url, "_self");
                }
            }
            else {
                // the event came from duo, do the post back
                doPostBack(event.data);

                // always clean up after yourself!
                offMessage(onReceivedMessage);
            }
        }
    }

    /**
     * Validate that this passed in URL is one that we will actually allow to
     * be opened.
     * @param url String URL that the message poster wants to open
     * @returns {boolean} true if we allow this url to be opened in the window
     */
    function isValidUrlToOpen(url) {
        if (!url) {
            return false;
        }

        var parser = document.createElement('a');
        parser.href = url;

        if (parser.protocol === "duotrustedendpoints:") {
            return true;
        } else if (parser.protocol !== "https:") {
            return false;
        }

        for (var i = 0; i < VALID_OPEN_WINDOW_DOMAINS.length; i++) {
           if (parser.hostname.endsWith("." + VALID_OPEN_WINDOW_DOMAINS[i]) ||
                   parser.hostname === VALID_OPEN_WINDOW_DOMAINS[i]) {
               return true;
           }
        }
        return false;
    }

    /**
     * Register a callback to call ready() after the DOM has loaded.
     */
    function asyncReady(options) {
        var callback = function() {
            var promptElement = getPromptElement(options);
            if (!promptElement) {
                throwError(
                    'This page does not contain an iframe for Duo to use.' +
                    ' Add an element like' +
                    ' <iframe id="duo_iframe"></iframe> to this page.'
                );
            }

            ready(promptElement, options.iframeAttributes || {});

            // Always clean up after yourself.
            offReady(callback)
        };

        onReady(callback);
    }

    /**
     * Point the iframe at Duo, then wait for it to postMessage back to us.
     */
    function ready(promptElement, iframeAttributes) {
        if (!host) {
            host = getDataAttribute(promptElement, 'host');

            if (!host) {
                throwError(
                    'No API hostname is given for Duo to use.  Be sure to pass ' +
                    'a `host` parameter to Duo.init, or through the `data-host` ' +
                    'attribute on the iframe element.'
                );
            }
        }

        if (!duoSig || !appSig) {
            parseSigRequest(getDataAttribute(promptElement, 'sigRequest'));

            if (!duoSig || !appSig) {
                throwError(
                    'No valid signed request is given.  Be sure to give the ' +
                    '`sig_request` parameter to Duo.init, or use the ' +
                    '`data-sig-request` attribute on the iframe element.'
                );
            }
        }

        // if postAction/Argument are defaults, see if they are specified
        // as data attributes on the iframe
        if (postAction === '') {
            postAction = getDataAttribute(promptElement, 'postAction') || postAction;
        }

        if (postArgument === 'sig_response') {
            postArgument = getDataAttribute(promptElement, 'postArgument') || postArgument;
        }

        if (isIframe(promptElement)) {
            iframe = promptElement;
            iframe.src = generateIframeSrc();
        } else {
            // If given a container to put an iframe in, clean out any children
            // child elements in case `init()` was called more than once.
            while (promptElement.firstChild) {
                // We call `removeChild()` instead of doing `innerHTML = ""`
                // to make sure we unbind any events.
                promptElement.removeChild(promptElement.firstChild)
            }

            iframe = document.createElement('iframe');

            // Set the src and all other attributes on the new iframe.
            iframeAttributes['src'] = generateIframeSrc();
            for (var name in iframeAttributes) {
                iframe.setAttribute(name, iframeAttributes[name]);
            }

            promptElement.appendChild(iframe);
        }

        // listen for the 'message' event
        onMessage(onReceivedMessage);
    }

    /**
     * We received a postMessage from Duo.  POST back to the primary service
     * with the response token, and any additional user-supplied parameters
     * given in form#duo_form.
     */
    function doPostBack(response) {
        // create a hidden input to contain the response token
        var input = document.createElement('input');
        input.type = 'hidden';
        input.name = postArgument;
        input.value = response + ':' + appSig;

        // user may supply their own form with additional inputs
        var form = document.getElementById('duo_form');

        // if the form doesn't exist, create one
        if (!form) {
            form = document.createElement('form');

            // insert the new form after the iframe
            iframe.parentElement.insertBefore(form, iframe.nextSibling);
        }

        // make sure we are actually posting to the right place
        form.method = 'POST';
        form.action = postAction;

        // add the response token input to the form
        form.appendChild(input);

        // away we go!
        if (typeof submitCallback === "function") {
            submitCallback.call(null, form);
        } else {
            form.submit();
        }
    }

    return {
        init: init,
        _onReady: onReady,
        _parseSigRequest: parseSigRequest,
        _isDuoMessage: isDuoMessage,
        _doPostBack: doPostBack
    };
}));
duo_php/demos/simple/Duo-Frame.css000064400000000175147361031610013100 0ustar00#duo_iframe {
    width: 100%;
    min-width: 304px;
    max-width: 620px;
    height: 330px;
    background: transparent;
}
duo_php/demos/simple/index.php000064400000005322147361031610012426 0ustar00<?php
/*
 * Simple Demo of Duo's Web SDK
 *
 * Simple login form with hardcoded username/password
 * protected using Duo
 */

require_once '../../src/Web.php';

define('USERNAME', 'demo');
define('PASSWORD', 'letmein');

/*
 * This is something uniquely generated by you for your application
 * and is not shared with Duo.
 */
define('AKEY', "THISISMYSUPERSECRETCUSTOMERKEYDONOTSHARE");

/*
 * IKEY, SKEY, and HOST should come from the Duo Security admin dashboard
 * on the integrations page. For security reasons, these keys are best stored
 * outside of the webroot in a production implementation.
 */
define('IKEY', "");
define('SKEY', "");
define('HOST', "");

echo "<html>";
echo '<head>';
echo '<meta http-equiv="X-UA-Compatible" content="IE=edge">';
echo '<meta name="viewport" content="width=device-width, initial-scale=1">';
echo '</head>';
echo "<h1>Duo Security Web SDK Demo</h1>";
echo sprintf("Username: %s <br>Password: %s <br><br><br><hr>", USERNAME, PASSWORD);

/*
 * STEP 3:
 * Once secondary auth has completed you may log in the user
 */
if (isset($_POST['sig_response'])) {
    /*
     * Verify sig response and log in user. Make sure that verifyResponse
     * returns the username we logged in with. You can then set any
     * cookies/session data for that username and complete the login process.
     */
    $resp = Duo\Web::verifyResponse(IKEY, SKEY, AKEY, $_POST['sig_response']);
    if ($resp === USERNAME) {
        // Password protected content would go here.
        echo 'Hi, ' . $resp . '<br>';
        echo 'Your content here!';
    }
}

/*
 * STEP 2:
 * verify username and password
 * if the user and pass are good, then generate a sig_request and
 * load up the Duo iframe for secondary authentication
 */
else if (isset($_POST['user']) && isset($_POST['pass'])) {
    if ($_POST['user'] === USERNAME && $_POST['pass'] === PASSWORD) {
        /*
         * Perform secondary auth, generate sig request, then load up Duo
         * javascript and iframe.
         */
        $sig_request = Duo\Web::signRequest(IKEY, SKEY, AKEY, $_POST['user']);
    ?>
        <script type="text/javascript" src="Duo-Web-v2.js"></script>
        <link rel="stylesheet" type="text/css" href="Duo-Frame.css">
        <iframe id="duo_iframe"
            data-host="<?php echo HOST; ?>"
            data-sig-request="<?php echo $sig_request; ?>"
        ></iframe>
<?php
    }
}

/*
 * STEP 1: login form
 * handled exactly as usual
 */
else {
    // Output simple login form
    echo "<form action='index.php' method='post'>";
    echo "Username: <input type='text' name='user' /> <br />";
    echo "Password: <input type='password' name='pass' /> <br />";
    echo "<input type='submit' value='Submit' />";
    echo "</form>";
}

echo "</html>";

?>