{% extends 'layout.html'%}

{%block content%}

<div class="row">
    <div class="col-md-6">
        <h1>Generate Device Code</h1>
    <form class="row g-3" id="device_code_form">
        <div class="col-auto" id="api_version">
            <div class="btn-group" role="group">
                <span class="input-group-text" style="border-top-right-radius: 0px; border-bottom-right-radius: 0px;">API Version</span>
                <input type="radio" class="btn-check" name="btnradio" id="api_version_1" autocomplete="off" value="1" checked>
                <label class="btn btn-outline-primary" for="api_version_1">v1</label>
                <input type="radio" class="btn-check" name="btnradio" id="api_version_2" autocomplete="off" value="2">
                <label class="btn btn-outline-primary" for="api_version_2">v2</label>
            </div>
        </div>
        <div class="col-auto" id="auto_action">
            <div class="btn-group" role="group">
                <span class="input-group-text" style="border-top-right-radius: 0px; border-bottom-right-radius: 0px;">Auto Action</span>
                <input type="radio" class="btn-check" name="auto_action_radio" id="auto_action_none" autocomplete="off" value="none" checked>
                <label class="btn btn-outline-primary" for="auto_action_none">None</label>
                <input type="radio" class="btn-check" name="auto_action_radio" id="auto_action_prt" autocomplete="off" value="device_prt">
                <label class="btn btn-outline-primary" for="auto_action_prt">Device PRT</label>
                <input type="radio" class="btn-check" name="auto_action_radio" id="auto_action_winhello" autocomplete="off" value="winhello">
                <label class="btn btn-outline-primary" for="auto_action_winhello">Winhello</label>
            </div>
        </div>
        <div id="resource_container" class="col-12">
            <div class="input-group">
                <span class="input-group-text">Resource</span>
                <input list="resource_list" id="resource_input" class="form-control" placeholder="https://graph.microsoft.com">
                <datalist id="resource_list">
                    <option value="https://graph.microsoft.com">MSGraph</option>
                    <option value="https://graph.windows.net/">AAD Graph</option>
                    <option value="https://outlook.office365.com">Outlook</option>
                    <option value="https://api.spaces.skype.com/">MSTeams</option>
                    <option value="https://management.core.windows.net/">AzureCoreManagement</option>
                    <option value="https://management.azure.com">AzureManagement</option>
                    <option value="urn:ms-drs:enterpriseregistration.windows.net">Entra ID Device Join</option>
                </datalist>
            </div>
        </div>
        <div id="scope_container" class="col-12" style="display: none;">
            <div class="input-group">
                <span class="input-group-text">Scope</span>
                <input list="scope_list" id="scope_input" class="form-control" placeholder="https://graph.microsoft.com/.default openid offline_access">
                <datalist id="scope_list">
                    <option value="https://graph.microsoft.com/.default openid offline_access">MSGraph</option>
                    <option value="https://graph.windows.net/.default openid offline_access">AAD Graph</option>
                    <option value="https://outlook.office365.com/.default openid offline_access">Outlook</option>
                    <option value="https://api.spaces.skype.com/.default openid offline_access">MSTeams</option>
                    <option value="https://management.core.windows.net/.default openid offline_access">AzureCoreManagement</option>
                    <option value="https://management.azure.com/.default openid offline_access">AzureManagement</option>
                    <option value="19db86c3-b2b9-44cc-b339-36da233a3be2/.default openid offline_access">My Signins</option>
                    <option value="urn:ms-drs:enterpriseregistration.windows.net/.default openid offline_access">Entra ID Device Join</option>
                </datalist>
            </div>
        </div>
        <div class="col-12">
            <div class="input-group">
                <span class="input-group-text">Client ID</span>
                <input list="client_id_list" id="client_id_input" class="form-control" placeholder="d3590ed6-52b3-4102-aeff-aad2292ab01c">
                <datalist id="client_id_list">
                    <option value="d3590ed6-52b3-4102-aeff-aad2292ab01c">Microsoft Office</option>
                    <option value="1fec8e78-bce4-4aaf-ab1b-5451cc387264">Microsoft Teams</option>
                    <option value="27922004-5251-4030-b22d-91ecd9a37ea4">Outlook Mobile</option>
                    <option value="b26aadf8-566f-4478-926f-589f601d9c74">OneDrive</option>
                    <option value="d326c1ce-6cc6-4de2-bebc-4591e5e13ef0">SharePoint</option>
                    <option value="00b41c95-dab0-4487-9791-b9d2c32c80f2">Office 365 Management</option>
                    <option value="04b07795-8ddb-461a-bbee-02f9e1bf7b46">Microsoft Azure CLI</option>
                    <option value="1950a258-227b-4e31-a9cf-717495945fc2">Microsoft Azure PowerShell</option>
                    <option value="29d9ed98-a469-4536-ade2-f981bc1d605e">Microsoft Authentication Broker</option>
                </datalist>
            </div>
        </div>
        <div>
            <div>
                <input type="checkbox" id="ngcmfa_checkbox" class="form-check-input">
                <label for="ngcmfa_checkbox" class="form-check-label" id="ngcmfa_tooltip" data-bs-toggle="tooltip" data-bs-placement="right" data-bs-title="Access tokens with the ngcmfa claim can be used for 15 minutes to register FIDO security keys or enroll Windows Hello for Business. Note: this will force the victim to authenticate with MFA during the device code authentication!">Request ngcmfa claim</label>
            </div>
            <div id="cae_container" style="display: none;">
                <input type="checkbox" id="cae_checkbox" class="form-check-input">
                <label for="cae_checkbox" class="form-check-label" id="cae_tooltip" data-bs-toggle="tooltip" data-bs-placement="right" data-bs-title="Request an access token with Continuous Access Evaluation (CAE) claims. Note: Access tokens with CAE will be valid for longer, however, they can instantly be revoked based on user risk or location changes!">Request CAE claim</label>
            </div>
        </div>
        <div id="auto_fields_container" class="col-12" style="display: none;">
            <div class="row g-2">
                <div class="col-md-6">
                    <div class="input-group">
                        <label for="device_name" class="input-group-text">Device Name</label>
                        <input type="text" id="device_name" name="device_name" class="form-control" placeholder="GraphSpy-Device">
                    </div>
                </div>
                <div class="col-md-6">
                    <div class="input-group">
                        <label for="join_type" class="input-group-text">Join Type</label>
                        <select id="join_type" name="join_type" class="form-select">
                            <option value="0">Entra ID Joined</option>
                            <option value="4">Entra ID Registered</option>
                        </select>
                    </div>
                </div>
                <div class="col-md-6">
                    <div class="input-group">
                        <label for="device_type" class="input-group-text">Device Type</label>
                        <input type="text" id="device_type" name="device_type" class="form-control" placeholder="Windows">
                    </div>
                </div>
                <div class="col-md-6">
                    <div class="input-group">
                        <label for="os_version" class="input-group-text">OS Version</label>
                        <input type="text" id="os_version" name="os_version" class="form-control" placeholder="10.0.26100">
                    </div>
                </div>
                <div class="col-md-6">
                    <div class="input-group">
                        <label for="target_domain" class="input-group-text">Target Domain</label>
                        <input type="text" id="target_domain" name="target_domain" class="form-control" placeholder="e-corp.local">
                    </div>
                </div>
            </div>
        </div>
        <div>
            <button type="button" class="btn btn-primary" onclick="generateDeviceCodeButton();">Generate Device Code</button>
        </div>
    </form>
    </div>
    <div class="col-md-6 mt-4">
        <!-- Device Login URLs - positioned at bottom of right column -->
        <div class="card w-auto d-inline-block float-end">
            <div class="card-header py-2">
                <h6 class="card-title mb-0">Device Login URLs</h6>
            </div>
            <div class="card-body py-2">
                <div class="d-flex flex-column gap-1">
                    <div class="d-flex align-items-center gap-2">
                        <button type="button" class="btn btn-sm btn-outline-primary" onclick="copyToClipboard('https://login.microsoftonline.com/common/oauth2/deviceauth')" title="Copy URL">
                            <i class="fi fi-rr-copy-alt"></i>
                        </button>
                        <small class="text-break">https://login.microsoftonline.com/common/oauth2/deviceauth</small>
                    </div>
                    <div class="d-flex align-items-center gap-2">
                        <button type="button" class="btn btn-sm btn-outline-primary" onclick="copyToClipboard('https://login.microsoft.com/common/oauth2/deviceauth')" title="Copy URL">
                            <i class="fi fi-rr-copy-alt"></i>
                        </button>
                        <small class="text-break">https://login.microsoft.com/common/oauth2/deviceauth</small>
                    </div>
                    <div class="d-flex align-items-center gap-2">
                        <button type="button" class="btn btn-sm btn-outline-primary" onclick="copyToClipboard('https://microsoft.com/devicelogin')" title="Copy URL">
                            <i class="fi fi-rr-copy-alt"></i>
                        </button>
                        <small class="text-break">https://microsoft.com/devicelogin</small>
                    </div>
                    <div class="d-flex align-items-center gap-2">
                        <button type="button" class="btn btn-sm btn-outline-primary" onclick="copyToClipboard('https://aka.ms/devicelogin')" title="Copy URL">
                            <i class="fi fi-rr-copy-alt"></i>
                        </button>
                        <small class="text-break">https://aka.ms/devicelogin</small>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
<script>
    new bootstrap.Tooltip(document.getElementById('ngcmfa_tooltip'));
    new bootstrap.Tooltip(document.getElementById('cae_tooltip'));
    
    $("#device_code_form #api_version").on('click', 'input', function (e) {
        if ($(e.target).val() == "1") {
            $("#resource_container").show();
            $("#scope_container").hide();
            $("#cae_container").hide();
        } else if ($(e.target).val() == "2") {
            $("#resource_container").hide();
            $("#scope_container").show();
            $("#cae_container").show();
        }
    });

    $("#device_code_form #auto_action").on('click', 'input', function (e) {
        const autoAction = $(e.target).val();
        if (autoAction === "none") {
            $("#auto_fields_container").hide();
        } else {
            $("#auto_fields_container").show();
            // Set default values for device registration
            $("#resource_input").val("urn:ms-drs:enterpriseregistration.windows.net");
            $("#scope_input").val("urn:ms-drs:enterpriseregistration.windows.net/.default openid offline_access");
            $("#client_id_input").val("29d9ed98-a469-4536-ade2-f981bc1d605e");
        }
        if (autoAction === "winhello") {
            // Force ngcmfa to be true for winhello
            $("#ngcmfa_checkbox").prop("checked", true);
        }
    });
</script>
<br>
<div>
    <h1>Device Code List</h1>
    <button type="button" class="btn btn-primary" onclick="restartDeviceCodePolling()">Restart Polling</button>
    <table id="device_codes" class="table" style="table-layout:fixed; width:100%">
    </table>
</div>
<script type="text/javascript" class="init">
    // Populate the device_codes table
    let myTable = new DataTable('#device_codes', {
        ajax: {
            url: '/api/list_device_codes', dataSrc: ""
        },
        columns: [
            {
                className: 'dt-control',
                orderable: false,
                data: null,
                defaultContent: '',
                'width': '40px'
            },
            {
                className: 'copy-control',
                orderable: false,
                data: null,
                defaultContent: '<i class="fi fi-rr-copy-alt" style="cursor: pointer"></i>',
                'width': '40px'
            },
            {
                className: 'delete-control',
                orderable: false,
                data: null,
                defaultContent: '<i class="fi fi-rr-trash" style="cursor: pointer"></i>',
                'width': '40px'
            },
            { data: 'id', title: 'ID', 'width': '60px' },
            { data: 'generated_at', title: 'Generated At', 'width': '170px' },
            { data: 'expires_at', title: 'Expires At', 'width': '170px' },
            { data: 'last_poll', title: 'Last Polled At', 'width': '170px' },
            { data: 'user_code', title: 'User Code', 'width': '145px' },
            { data: 'client_id', title: 'Client ID', 'width': '330px' },
            { data: 'auto_action', title: 'Auto Action', 'width': '145px' },
            { data: 'status', title: 'Status' }
        ],
        order: [[3, 'desc']],
        colReorder: {
            columns: ':gt(2)'
        },
        createdRow: function (row, data, dataIndex) {
            switch (data.status) {
                case "SUCCESS":
                    $(row).children().addClass('bg-success-subtle').addClass('text-success-emphasis');
                    break;
                case "PARTIAL_SUCCESS":
                    $(row).children().addClass('bg-warning-subtle').addClass('text-warning-emphasis');
                    break;
                case "ACTION_IN_PROGRESS":
                    $(row).children().addClass('bg-info-subtle').addClass('text-info-emphasis');
                    break;
                case "EXPIRED":
                    $(row).children().addClass('bg-danger-subtle').addClass('text-danger-emphasis');
                    break;
                default:
                    $(row).children().addClass('bg-primary-subtle').addClass('text-primary-emphasis');
            }
        }
    })

    myTable.on('click', 'td.dt-control', function (e) {
        let tr = e.target.closest('tr');
        let row = myTable.row(tr);

        if (row.child.isShown()) {
            // This row is already open - close it
            row.child.hide();
        }
        else {
            // Open this row
            row.child(format(row.data())).show();
            Prism.highlightAll();
        }
    });

    myTable.on('click', 'td.copy-control', function (e) {
        let tr = e.target.closest('tr');
        let row = myTable.row(tr);
        copyToClipboard(row.data().user_code);
    });

    myTable.on('click', 'td.delete-control', function (e) {
        let tr = e.target.closest('tr');
        let row = myTable.row(tr);
        if (!confirm("Are you sure you want to delete device code with ID " + row.data().id + "?")) { return }
        deleteDeviceCode(row.data().id);
    });

    function format(d) {
        var formatWrapper = $(
            '<dl>' +
            '<dt>Raw Token:</dt>' +
            '</dl>'
        );
        var formatPre = formatJsonCode(d);
        formatWrapper.append($('<dd></dd>').append(formatPre));
        return formatWrapper;
    }

    function deleteDeviceCode(id) {
        let response = $.ajax({
            type: "GET",
            async: false,
            url: "/api/delete_device_code/" + id
        });
        $('#device_codes').DataTable().ajax.reload(null, false);
    }

    function generateDeviceCodeButton(){
        const autoAction = $('input[name="auto_action_radio"]:checked').val();
        
        generateDeviceCode(
            parseInt($('#api_version input:radio:checked').val()), 
            client_id_input.value, 
            resource_input.value,
            scope_input.value,
            ngcmfa_checkbox.checked,
            cae_checkbox.checked,
            autoAction !== "none" ? autoAction : undefined,
            autoAction !== "none" ? $("#device_name").val() : undefined,
            autoAction !== "none" ? $("#join_type").val() : undefined,
            autoAction !== "none" ? $("#device_type").val() : undefined,
            autoAction !== "none" ? $("#os_version").val() : undefined,
            autoAction !== "none" ? $("#target_domain").val() : undefined
        );
    }

    // Auto refresh the table every 5 seconds
    setInterval(function () {
        $('#device_codes').DataTable().ajax.reload(null, false)
    }, 5000);
</script>
{%endblock content%}