GPT TEAM 无法打开 “允许外部域邀请 ”

sk-datatokes 2026-08-17 21:30 1

之前 TEAM 验证域名后,把允许外部域邀请关闭了。

今天想邀请别人,结果这里变灰了,无法打开。


1.云控制台 已验证域名还是存在的。


这下我的空间废了,有没有什么方法可以打开啊




最新回复 (2)
  • sk-datatokes 楼主 08-18 10:30
    1

    现在尝试联系客服,不知道能否解决

  • Zeraphine 08-18 11:50
    2

    写了个油猴脚本强开(AI搓的,这总不能截图发送吧)


    // ==UserScript==
    // @name ChatGPT 外部域名邀请设置
    // @namespace https://github.com/openai-tools/userscripts
    // @version 1.1.0
    // @description 通过悬浮面板开关 allow_external_domain_invites 设置
    // @author local
    // @match https://chatgpt.com/admin/identity*
    // @grant GM_addStyle
    // @grant GM_getValue
    // @grant GM_setValue
    // @noframes
    // @run-at document-idle
    // ==/UserScript==

    (function () {
    "use strict";

    if (
    location.pathname !== "/admin/identity" ||
    !document.body ||
    document.getElementById("aed-invites-root")
    ) {
    return;
    }

    const STORAGE_KEYS = {
    enable: "allowExternalDomainInvites.enable",
    };

    const initialEnable = GM_getValue(STORAGE_KEYS.enable, true);

    GM_addStyle(`
    #aed-invites-root {
    position: fixed;
    right: 20px;
    bottom: 20px;
    z-index: 2147483647;
    color: #1f2937;
    font: 14px/1.4 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    }
    #aed-invites-root * { box-sizing: border-box; }
    #aed-invites-toggle {
    border: 0;
    border-radius: 999px;
    padding: 10px 14px;
    color: #fff;
    background: #10a37f;
    box-shadow: 0 4px 18px rgb(0 0 0 / 22%);
    cursor: pointer;
    font: inherit;
    }
    #aed-invites-toggle:hover { background: #0d8e6f; }
    #aed-invites-panel {
    display: none;
    width: min(360px, calc(100vw - 32px));
    margin-bottom: 10px;
    padding: 16px;
    border: 1px solid rgb(0 0 0 / 12%);
    border-radius: 12px;
    background: #fff;
    box-shadow: 0 8px 30px rgb(0 0 0 / 20%);
    }
    #aed-invites-panel.aed-open { display: block; }
    #aed-invites-title {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: 12px;
    font-weight: 600;
    }
    #aed-invites-close {
    border: 0;
    padding: 0 4px;
    color: #6b7280;
    background: transparent;
    cursor: pointer;
    font-size: 20px;
    line-height: 1;
    }
    #aed-invites-panel label { display: block; margin: 10px 0 6px; }
    #aed-invites-workspace {
    display: block;
    min-height: 36px;
    padding: 8px 10px;
    border: 1px solid #d1d5db;
    border-radius: 6px;
    overflow-wrap: anywhere;
    color: inherit;
    background: #f9fafb;
    font: 13px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace;
    }
    #aed-invites-refresh {
    margin-top: 7px;
    padding: 0;
    border: 0;
    color: #0d8e6f;
    background: transparent;
    cursor: pointer;
    font: inherit;
    font-size: 12px;
    }
    #aed-invites-refresh:disabled { cursor: wait; opacity: .65; }
    #aed-invites-enable-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 12px 0;
    cursor: pointer;
    }
    #aed-invites-enable { width: 16px; height: 16px; margin: 0; }
    #aed-invites-submit {
    width: 100%;
    padding: 9px 12px;
    border: 0;
    border-radius: 6px;
    color: #fff;
    background: #10a37f;
    cursor: pointer;
    font: inherit;
    }
    #aed-invites-submit:disabled { cursor: wait; opacity: .65; }
    #aed-invites-status {
    min-height: 20px;
    margin-top: 10px;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    font-size: 12px;
    }
    #aed-invites-status.aed-success { color: #087f5b; }
    #aed-invites-status.aed-error { color: #c92a2a; }
    #aed-invites-hint { margin-top: 8px; color: #6b7280; font-size: 12px; }
    @media (prefers-color-scheme: dark) {
    #aed-invites-panel { border-color: rgb(255 255 255 / 15%); color: #f3f4f6; background: #202123; }
    #aed-invites-workspace { border-color: #4b5563; color: inherit; background: #343541; }
    #aed-invites-close { color: #9ca3af; }
    }
    `);

    const root = document.createElement("div");
    root.id = "aed-invites-root";
    root.innerHTML = `
    <section id="aed-invites-panel" aria-label="外部域名邀请设置">
    <div id="aed-invites-title">
    <span>外部域名邀请设置</span>
    <button id="aed-invites-close" type="button" title="关闭">×</button>
    </div>
    <label for="aed-invites-workspace">Workspace ID(自动获取)</label>
    <div id="aed-invites-workspace" role="textbox" aria-readonly="true">正在获取…</div>
    <button id="aed-invites-refresh" type="button">重新获取 Workspace ID</button>
    <label id="aed-invites-enable-row" for="aed-invites-enable">
    <input id="aed-invites-enable" type="checkbox" ${initialEnable ? "checked" : ""}>
    <span>允许外部域名邀请</span>
    </label>
    <button id="aed-invites-submit" type="button" disabled>保存设置</button>
    <div id="aed-invites-status" role="status" aria-live="polite"></div>
    <div id="aed-invites-hint">请求使用当前页面的登录会话发送。</div>
    </section>
    <button id="aed-invites-toggle" type="button">外部邀请</button>
    `;
    document.body.appendChild(root);

    const panel = root.querySelector("#aed-invites-panel");
    const toggle = root.querySelector("#aed-invites-toggle");
    const close = root.querySelector("#aed-invites-close");
    const workspaceValue = root.querySelector("#aed-invites-workspace");
    const refresh = root.querySelector("#aed-invites-refresh");
    const enableInput = root.querySelector("#aed-invites-enable");
    const submit = root.querySelector("#aed-invites-submit");
    const status = root.querySelector("#aed-invites-status");
    let workspaceId = "";

    toggle.addEventListener("click", () => {
    panel.classList.toggle("aed-open");
    if (panel.classList.contains("aed-open")) refresh.focus();
    });
    close.addEventListener("click", () => panel.classList.remove("aed-open"));
    refresh.addEventListener("click", refreshWorkspaceId);

    submit.addEventListener("click", async () => {
    const enable = enableInput.checked;

    if (!workspaceId) {
    showStatus("尚未获取到 Workspace ID,请点击“重新获取”。", "error");
    return;
    }

    GM_setValue(STORAGE_KEYS.enable, enable);
    submit.disabled = true;
    showStatus("正在提交…");

    try {
    await updateSetting(workspaceId, enable);
    showStatus("保存成功,正在刷新页面…", "success");
    window.location.reload();
    } catch (error) {
    showStatus(`设置失败:${error.message}`, "error");
    } finally {
    submit.disabled = false;
    }
    });

    refreshWorkspaceId();

    function showStatus(message, type) {
    status.textContent = message;
    status.className = type ? `aed-${type}` : "";
    }

    async function refreshWorkspaceId() {
    refresh.disabled = true;
    submit.disabled = true;
    workspaceValue.textContent = "正在获取…";
    showStatus("正在自动获取 Workspace ID…");

    try {
    const detected = await detectWorkspaceId();
    workspaceId = detected.id;
    workspaceValue.textContent = workspaceId;
    submit.disabled = false;
    showStatus(`已获取 Workspace ID(${detected.source})。`, "success");
    } catch (error) {
    workspaceId = "";
    workspaceValue.textContent = "未找到";
    showStatus(`自动获取失败:${error.message}`, "error");
    } finally {
    refresh.disabled = false;
    }
    }

    async function updateSetting(workspaceId, enable) {
    const authorization = await getAuthorization();
    const encodedWorkspaceId = encodeURIComponent(workspaceId);
    const apiPath =
    `/backend-api/accounts/${encodedWorkspaceId}` +
    "/settings/allow_external_domain_invites";

    const response = await fetch(apiPath, {
    method: "POST",
    credentials: "include",
    headers: {
    Accept: "application/json",
    "Content-Type": "application/json",
    Authorization: authorization,
    "chatgpt-account-id": workspaceId,
    "x-openai-target-path": apiPath,
    "x-openai-target-route":
    "/backend-api/accounts/{account_id}/settings/allow_external_domain_invites",
    },
    body: JSON.stringify({ value: enable }),
    });

    const result = await response.text();
    if (!response.ok) throw new Error(`请求失败 (${response.status})${result ? `:${result}` : ""}`);
    }

    async function detectWorkspaceId() {
    const pageId = findWorkspaceId(readPageData());
    if (pageId) return { id: pageId, source: "当前页面" };

    const { session, authorization } = await getSession();
    const sessionId = findWorkspaceId(session);
    if (sessionId) return { id: sessionId, source: "登录 session" };

    const endpoints = ["/backend-api/accounts", "/backend-api/accounts/check"];
    for (const endpoint of endpoints) {
    let response;
    try {
    response = await fetch(endpoint, {
    method: "GET",
    credentials: "include",
    headers: { Accept: "application/json", Authorization: authorization },
    });
    } catch {
    continue;
    }
    if (!response.ok) continue;

    let data;
    try {
    data = await response.json();
    } catch {
    continue;
    }

    const id = findWorkspaceId(data);
    if (id) return { id, source: endpoint };
    }

    throw new Error("页面数据和账号接口都没有返回可用的 Workspace ID");
    }

    async function getSession() {
    const sessionResponse = await fetch("/api/auth/session", {
    method: "GET",
    credentials: "include",
    cache: "no-store",
    });

    if (!sessionResponse.ok) {
    throw new Error(`获取 session 失败 (${sessionResponse.status})`);
    }

    const session = await sessionResponse.json();
    const accessToken = session?.accessToken;
    if (!accessToken) {
    throw new Error("session 中没有 accessToken,请确认当前页面已登录");
    }

    const authorization = /^Bearer\s/i.test(accessToken)
    ? accessToken
    : `Bearer ${accessToken}`;
    return { session, authorization };
    }

    async function getAuthorization() {
    return (await getSession()).authorization;
    }

    function readPageData() {
    const data = [];
    if (window.__NEXT_DATA__) data.push(window.__NEXT_DATA__);
    if (window.__INITIAL_STATE__) data.push(window.__INITIAL_STATE__);

    for (const script of document.scripts) {
    if (script.id !== "__NEXT_DATA__" && script.type !== "application/json") continue;
    const text = script.textContent?.trim();
    if (!text) continue;
    try {
    data.push(JSON.parse(text));
    } catch {
    // 某些页面脚本不是 JSON,跳过即可。
    }
    }

    const text = document.body?.innerText || "";
    const labeledId = text.match(
    /(?:workspace|account)\s*id\s*[::]?\s*([A-Za-z0-9][A-Za-z0-9_-]{5,})/i,
    );
    if (labeledId) data.push({ workspace_id: labeledId[1] });
    return data;
    }

    function findWorkspaceId(value) {
    if (!value || typeof value !== "object") return "";

    const mapId = findIdInAccountMap(value, "", new Set());
    if (mapId) return mapId;

    const currentObject = findCurrentObject(value, new Set());
    const currentId = currentObject && findIdByKey(currentObject, new Set());
    if (currentId) return currentId;

    const directId = findIdByKey(value, new Set());
    if (directId) return directId;
    return collectIds(value, [], new Set())[0] || "";
    }

    function findIdInAccountMap(value, parentKey, seen) {
    if (!value || typeof value !== "object" || seen.has(value)) return "";
    seen.add(value);

    const isAccountMap = /^(?:accounts?|workspaces?)$/i.test(parentKey);
    const isAccountObject = /^(?:account|workspace)$/i.test(parentKey);
    if (isAccountObject && typeof value.id === "string" && value.id.trim()) {
    return value.id.trim();
    }
    if (isAccountMap) {
    if (Array.isArray(value)) {
    for (const child of value) {
    if (child && typeof child.id === "string" && child.id.trim()) {
    return child.id.trim();
    }
    }
    } else {
    for (const key of Object.keys(value)) {
    if (isLikelyWorkspaceId(key)) return key;
    }
    }
    }
    for (const [key, child] of Object.entries(value)) {
    const id = findIdInAccountMap(child, key, seen);
    if (id) return id;
    }
    return "";
    }

    function findIdByKey(value, seen) {
    if (!value || typeof value !== "object" || seen.has(value)) return "";
    seen.add(value);

    for (const [key, child] of Object.entries(value)) {
    if (isWorkspaceIdKey(key) && typeof child === "string" && child.trim()) {
    return child.trim();
    }
    }
    for (const child of Object.values(value)) {
    const id = findIdByKey(child, seen);
    if (id) return id;
    }
    return "";
    }

    function collectIds(value, result, seen) {
    if (!value || typeof value !== "object" || seen.has(value)) return result;
    seen.add(value);

    for (const [key, child] of Object.entries(value)) {
    if (isWorkspaceIdKey(key) && typeof child === "string" && child.trim()) {
    result.push(child.trim());
    }
    collectIds(child, result, seen);
    }
    return result;
    }

    function findCurrentObject(value, seen) {
    if (!value || typeof value !== "object" || seen.has(value)) return null;
    seen.add(value);

    if (
    value.is_current === true ||
    value.isCurrent === true ||
    value.current === true ||
    value.selected === true ||
    value.active === true
    ) {
    return value;
    }
    for (const child of Object.values(value)) {
    const current = findCurrentObject(child, seen);
    if (current) return current;
    }
    return null;
    }

    function isWorkspaceIdKey(key) {
    return /^(?:current[_-]?)?(?:workspace|account)[_-]?id$/i.test(key);
    }

    function isLikelyWorkspaceId(value) {
    return (
    /^(?:org|workspace|account|team)[_-][A-Za-z0-9_-]{4,}$/i.test(value) ||
    /^[0-9a-f]{8}-[0-9a-f-]{27,}$/i.test(value)
    );
    }

    })();

* 帖子来源Linux.do
返回