function db_save_user_trusted_client($username, $client)
{
    $trusted_client = db_get_user_trusted_client($username, $client);
    if (!$trusted_client) {
        $account = db_get_user($username);
        $client = db_get_client($client);
        if ($account && $client) {
            $account->TrustedClients[] = $client;
            $account->save();
        }
    }
}
function handle_confirm_userinfo()
{
    $rpfA = $_SESSION['rpfA'];
    $client_id = $rpfA['client_id'];
    $authorized = false;
    if ($_REQUEST['confirm'] == 'confirmed') {
        if ($_REQUEST['agreed'] == "1") {
            $authorized = true;
        }
    }
    $trusted_site = db_get_user_trusted_client($_SESSION['username'], $client_id);
    if ($_REQUEST['trust'] == 'always') {
        log_debug("Trust = Always for %s", $client_id);
        if (!$trusted_site) {
            db_save_user_trusted_client($_SESSION['username'], $client_id);
        }
    } else {
        if ($trusted_site) {
            db_delete_user_trusted_client($_SESSION['username'], $client_id);
        }
    }
    send_response($_SESSION['username'], $authorized);
}
function webrtc_handle_auth()
{
    $state = isset($_REQUEST['state']) ? $_REQUEST['state'] : NULL;
    $error_page = OP_INDEX_PAGE;
    $response_mode = 'query';
    try {
        if (!isset($_REQUEST['client_id'])) {
            throw new OidcException('invalid_request', 'no client');
        }
        // check client id
        $client = db_get_client($_REQUEST['client_id']);
        if (!$client) {
            throw new OidcException('unauthorized_client', 'Client ID not found');
        }
        /*        if(isset($_REQUEST['redirect_uri'])) {
                    if(!is_valid_registered_redirect_uri($client['redirect_uris'], $_REQUEST['redirect_uri']))
                        throw new OidcException('invalid_request', 'no matching redirect_uri');
                } else
                    throw new OidcException('invalid_request', 'no redirect_uri in request');
        
                $error_page = $_REQUEST['redirect_uri'];
        */
        $response_mode = get_response_mode($_REQUEST);
        if (!isset($_REQUEST['response_type'])) {
            throw new OidcException('invalid_request', 'no response_type');
        }
        $response_types = explode(' ', $_REQUEST['response_type']);
        $known_response_types = array('code', 'token', 'id_token');
        if (count(array_diff($response_types, $known_response_types))) {
            throw new OidcException('invalid_response_type', "Unknown response_type {$_REQUEST['response_type']}");
        }
        if (ENABLE_PKCE) {
            if (in_array('code', $response_types)) {
                if (!isset($_REQUEST['code_challenge'])) {
                    throw new OidcException('invalid_request', 'code challenge required');
                }
                if (isset($_REQUEST['code_challenge_method'])) {
                    if (!in_array($_REQUEST['code_challenge_method'], array('plain', 'S256'))) {
                        throw new OidcException('invalid_request', "unsupported code challenge method {$_REQUEST['code_challenge_method']}");
                    }
                }
            }
        }
        if (!isset($_REQUEST['scope'])) {
            throw new OidcException('invalid_request', 'no scope');
        }
        $scopes = explode(' ', $_REQUEST['scope']);
        if (!in_array('openid', $scopes)) {
            throw new OidcException('invalid_scope', 'no openid scope');
        }
        if (in_array('token', $response_types) || in_array('id_token', $response_types)) {
            if (!isset($_REQUEST['nonce'])) {
                throw new OidcException('invalid_request', 'no nonce');
            }
        }
        $_SESSION['get'] = $_GET;
        $request_uri = isset($_REQUEST['request_uri']) ? $_REQUEST['request_uri'] : NULL;
        $requested_userid = NULL;
        $requested_userid_display = NULL;
        $request_object = NULL;
        if ($request_uri) {
            $request_object = get_url($request_uri);
            if (!$request_object) {
                throw new OidcException('invalid_request', "Unable to fetch request file {$request_uri}");
            }
        } elseif (isset($_REQUEST['request'])) {
            $request_object = $_REQUEST['request'];
        }
        if (isset($_GET['claims'])) {
            $_GET['claims'] = json_decode($_GET['claims'], true);
            $_REQUEST['claims'] = $_GET['claims'];
        }
        if (isset($request_object)) {
            $cryptoError = '';
            $payload = decrypt_verify_jwt($request_object, $client, $cryptoError);
            if (!isset($payload)) {
                if ($cryptoError == 'error_decrypt') {
                    throw new OidcException('invalid_request', 'Unable to decrypt request object');
                } elseif ($cryptoError == 'error_sig') {
                    throw new OidcException('invalid_request', 'Unable to verify request object signature');
                }
            } else {
                if (isset($payload['claims']['id_token'])) {
                    if (array_key_exists('sub', $payload['claims']['id_token']) && isset($payload['claims']['id_token']['sub']['value'])) {
                        $requested_userid_display = $payload['claims']['id_token']['sub']['value'];
                        $requested_userid = unwrap_userid($payload['claims']['id_token']['sub']['value']);
                        if (!db_get_user($requested_userid)) {
                            throw new OidcException('invalid_request', 'Unrecognized userid in request');
                        }
                    }
                }
                $merged_req = array_merge($_GET, $payload);
                if (!array_key_exists('max_age', $merged_req) && $client['default_max_age']) {
                    $merged_req['max_age'] = $client['default_max_age'];
                }
                if ($merged_req['max_age']) {
                    $merged_req['claims']['id_token']['auth_time'] = array('essential' => true);
                }
                if ((!$merged_req['claims']['id_token'] || !array_key_exists('auth_time', $merged_req['claims']['id_token'])) && $client['require_auth_time']) {
                    $merged_req['claims']['id_token']['auth_time'] = array('essential' => true);
                }
                if (!$merged_req['claims']['id_token'] || !array_key_exists('acr', $merged_req['claims']['id_token'])) {
                    if ($merged_req['acr_values']) {
                        $merged_req['claims']['id_token']['acr'] = array('essential' => true, 'values' => explode(' ', $merged_req['acr_values']));
                    } elseif ($client['default_acr_values']) {
                        $merged_req['claims']['id_token']['acr'] = array('essential' => true, 'values' => explode('|', $client['default_acr_values']));
                    }
                }
                $_SESSION['rpfA'] = $merged_req;
                log_debug("rpfA = %s", print_r($_SESSION['rpfA'], true));
                foreach (array('client_id', 'response_type', 'scope', 'nonce', 'redirect_uri') as $key) {
                    if (!isset($payload[$key])) {
                        log_error("missing %s in payload => %s", $key, print_r($payload, true));
                    }
                    //                      throw new OidcException('invalid_request', 'Request Object missing required parameters');
                }
                log_debug("payload => %s", print_r($payload, true));
                foreach ($payload as $key => $value) {
                    if (isset($_REQUEST[$key]) && strcmp($_REQUEST[$key], $value)) {
                        log_debug("key : %s value:%s", $key, print_r($value, true));
                        throw new OidcException('invalid_request', "Request Object Param Values do not match request '{$key}' '{$_REQUEST[$key]}' != '{$value}'");
                    }
                }
            }
        } else {
            if (isset($_GET['id_token_hint'])) {
                $cryptoError = '';
                $payload = decrypt_verify_jwt($_REQUEST['id_token_hint'], $client, $cryptoError);
                if (!isset($payload)) {
                    if ($cryptoError == 'error_decrypt') {
                        throw new OidcException('invalid_request', 'Unable to decrypt request object');
                    } elseif ($cryptoError == 'error_sig') {
                        throw new OidcException('invalid_request', 'Unable to verify request object signature');
                    }
                } else {
                    $requested_userid_display = $payload['sub'];
                    $requested_userid = unwrap_userid($payload['sub']);
                    if (!db_get_user($requested_userid)) {
                        throw new OidcException('invalid_request', 'Unrecognized userid in ID Token');
                    }
                }
            } else {
                if (isset($_GET['claims']['id_token']['sub']['value'])) {
                    $requested_userid_display = $_GET['claims']['id_token']['sub']['value'];
                    $requested_userid = unwrap_userid($_GET['claims']['id_token']['sub']['value']);
                    if (!db_get_user($requested_userid)) {
                        throw new OidcException('invalid_request', "Unrecognized userid in ID Token");
                    }
                } else {
                    if (isset($_GET['login_hint'])) {
                        $principal = $_GET['login_hint'];
                        $at = strpos($principal, '@');
                        if ($at !== false) {
                            error_log("EMAIL\n");
                            if ($at != 0) {
                                // XRI
                                // process email address
                                list($principal, $domain) = explode('@', $principal);
                                error_log("==> principal = {$principal} domain = {$domain}");
                                $port_pos = strpos($domain, ':');
                                if ($port_pos !== false) {
                                    $domain = substr($domain, 0, $port_pos);
                                }
                                $domain_parts = explode('.', $domain);
                                $server_parts = explode('.', OP_SERVER_NAME);
                                // check to see domain matches
                                $domain_start = count($domain_parts) - 1;
                                $server_start = count($server_parts) - 1;
                                $domain_match = true;
                                for ($i = $domain_start, $j = $server_start; $i >= 0 && $j >= 0; $i--, $j--) {
                                    if (strcasecmp($domain_parts[$i], $server_parts[$j]) != 0) {
                                        $domain_match = false;
                                    }
                                }
                                if ($domain_match) {
                                    $requested_userid_display = $principal;
                                    $requested_userid = unwrap_userid($requested_userid_display);
                                    if (!db_get_user($requested_userid)) {
                                        $requested_userid_display = NULL;
                                        $requested_userid = NULL;
                                    }
                                } else {
                                    throw new OidcException('invalid_request', 'Unrecognized email domain');
                                }
                            }
                        } else {
                            // name only
                            $requested_userid_display = $_GET['login_hint'];
                            $requested_userid = unwrap_userid($requested_userid_display);
                            if (!db_get_user($requested_userid)) {
                                $requested_userid_display = NULL;
                                $requested_userid = NULL;
                            }
                        }
                    }
                }
            }
            if (!array_key_exists('max_age', $_REQUEST) && $client['default_max_age']) {
                $_REQUEST['max_age'] = $client['default_max_age'];
            }
            if ($_REQUEST['max_age']) {
                $_REQUEST['claims']['id_token']['auth_time'] = array('essential' => true);
            }
            if ((!$_REQUEST['claims']['id_token'] || !array_key_exists('auth_time', $_REQUEST['claims']['id_token'])) && $client['require_auth_time']) {
                $_REQUEST['claims']['id_token']['auth_time'] = array('essential' => true);
            }
            if (!$_REQUEST['claims']['id_token'] || !array_key_exists('acr', $_REQUEST['claims']['id_token'])) {
                if ($_REQUEST['acr_values']) {
                    $_REQUEST['claims']['id_token']['acr'] = array('essential' => true, 'values' => explode(' ', $_REQUEST['acr_values']));
                } elseif ($client['default_acr_values']) {
                    $_REQUEST['claims']['id_token']['acr'] = array('essential' => true, 'values' => explode('|', $client['default_acr_values']));
                }
            }
            $_SESSION['rpfA'] = $_REQUEST;
        }
        log_debug("prompt = %s", $_SESSION['rpfA']['prompt']);
        $prompt = $_SESSION['rpfA']['prompt'] ? explode(' ', $_SESSION['rpfA']['prompt']) : array();
        $num_prompts = count($prompt);
        if ($num_prompts > 1 && in_array('none', $prompt)) {
            throw new OidcException('interaction_required', "conflicting prompt parameters {$_SESSION['rpfA']['prompt']}");
        }
        if (in_array('none', $prompt)) {
            $showUI = false;
        } else {
            $showUI = true;
        }
        log_debug("num prompt = %d %s", $num_prompts, print_r($prompt, true));
        if ($_SESSION['username']) {
            if (in_array('login', $prompt)) {
                echo loginform($requested_userid_display, $requested_userid, $client);
                exit;
            }
            if (isset($_SESSION['rpfA']['max_age'])) {
                if (time() - $_SESSION['auth_time'] > $_SESSION['rpfA']['max_age']) {
                    if (!$showUI) {
                        throw new OidcException('interaction_required', 'max_age exceeded and prompt set to none');
                    }
                    echo loginform($requested_userid_display, $requested_userid, $client);
                    exit;
                }
            }
            if ($requested_userid) {
                if ($_SESSION['username'] != $requested_userid) {
                    if (!$showUI) {
                        //                        throw new OidcException('interaction_required', 'requested account is different from logged in account, no UI requested');
                    } else {
                        //                        echo loginform($requested_userid_display, $requested_userid, $client);
                        exit;
                    }
                }
            }
            // if(in_array('consent', $prompt)){
            // echo confirm_userinfo();
            // exit();
            // }
            if (!db_get_user_trusted_client($_SESSION['username'], $_REQUEST['client_id'])) {
                if (!$showUI) {
                    throw new OidcException('interaction_required', 'consent needed and prompt set to none');
                }
                echo confirm_userinfo();
            } else {
                send_response_noRedirect($_SESSION['username'], true);
            }
        } else {
            // SBE Redirect to auth_time
            send_auth_response($request_uri, array(), $response_mode);
            //	header("Location: /auth?client_id=$client_id&response_type=$_REQUEST['response_type']&scope=$_REQUEST['scope']&nonce=$_REQUEST['nonce']");
            //            if(!$showUI)
            //                throw new OidcException('interaction_required', 'unauthenticated and prompt set to none');
            //            echo custom_loginform($requested_userid_display, $requested_userid, $client);
        }
    } catch (OidcException $e) {
        log_debug("handle_auth exception : %s", $e->getTraceAsString());
        send_error($error_page, $e->error_code, $e->desc, NULL, $state, $response_mode);
    } catch (Exception $e) {
        log_debug("handle_auth exception : %s", $e->getTraceAsString());
        send_error($error_page, 'invalid_request', $e->getMessage(), NULL, $state, $response_mode);
    }
}