获取微软激活确认ID,带悬浮面板,支持剪贴板操作和精准IID合法性校验*://visualsupport.microsoft.com/*
// ==UserScript==
// @name 获取确认ID免登录GM版
// @namespace http://tampermonkey.net/
// @version 2026-05-17 v1
// @description 获取微软激活确认ID,带悬浮面板,支持剪贴板操作和精准IID合法性校验*://visualsupport.microsoft.com/*
// @author 福建-兮
// @match *://visualsupport.microsoft.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=microsoft.com
// @grant GM_xmlhttpRequest
// @grant GM_setClipboard
// @connect visualsupport.microsoft.com
// @connect cidtoken.x2ray.cfd
// @license MIT
// ==/UserScript==
(function () {
'use strict';
/**
* 校验IID区块合法性
* @param {string} block - IID的单个区块
* @returns {boolean} 区块是否合法
*/
function checkBlock(block) {
if (!/^\d+$/.test(block) || block.length < 2) return false;
const check = Number(block.at(-1));
let sum = 0;
for (let i = 0; i < block.length - 1; i++) {
const d = Number(block[i]);
sum += i % 2 === 0 ? d : d * 2;
}
return sum % 7 === check;
}
/**
* 校验整个IID的合法性(增强版,返回具体错误信息)
* @param {string} iid - 待校验的IID字符串
* @returns {object} 校验结果 {valid: boolean, error?: string, failedBlocks?: array}
*/
function validateIID(iid) {
// 检查是否全为数字
if (!/^\d+$/.test(iid))
return { valid: false, error: "not_numeric" };
// 检查长度是否为54或63位
if (iid.length !== 54 && iid.length !== 63)
return { valid: false, error: "invalid_length", length: iid.length };
// 检查每个区块的合法性
const blockSize = iid.length / 9;
const failedBlocks = [];
for (let i = 0; i < 9; i++) {
const block = iid.slice(i * blockSize, (i + 1) * blockSize);
if (!checkBlock(block)) {
failedBlocks.push({
index: i + 1,
value: block
});
}
}
return {
valid: failedBlocks.length === 0,
failedBlocks
};
}
/**
* 创建悬浮提示框(通用,支持成功/错误提示)
* @param {string} mainText - 主要提示文本
* @param {string} detailText - 详细错误/成功信息
* @param {string} content - 额外展示的内容(IID/响应结果)
* @param {string} type - 提示类型(error/success)
* @param {number} duration - 显示时长(毫秒)
*/
function showFloatTip(mainText, detailText = "", content = "", type = "error", duration = 5000) {
// 移除已存在的提示框
const oldTip = document.getElementById("ms-iid-tip");
if (oldTip) oldTip.remove();
// 创建新提示框容器
const tipContainer = document.createElement("div");
tipContainer.id = "ms-iid-tip";
tipContainer.style.cssText = `
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
padding: 20px;
background: ${type === "error" ? "#f8d7da" : "#d4edda"};
color: ${type === "error" ? "#721c24" : "#155724"};
border: 1px solid ${type === "error" ? "#f5c6cb" : "#c3e6cb"};
border-radius: 8px;
font-size: 16px;
z-index: 9999999;
box-shadow: 0 4px 20px rgba(0,0,0,0.15);
opacity: 0;
transition: opacity 0.3s ease;
max-width: 80%;
max-height: 80vh;
overflow-y: auto;
word-break: break-all;
text-align: left;
`;
// 1. 主要提示文本
const tipTitle = document.createElement("div");
tipTitle.style.cssText = `
margin-bottom: 12px;
font-weight: bold;
font-size: 16px;
`;
tipTitle.textContent = mainText;
tipContainer.appendChild(tipTitle);
// 2. 详细信息(如有)
if (detailText) {
const tipDetail = document.createElement("div");
tipDetail.style.cssText = `
margin-bottom: 10px;
font-size: 14px;
line-height: 1.5;
`;
tipDetail.textContent = type === "error" ? `错误详情:${detailText}` : `响应信息:${detailText}`;
tipContainer.appendChild(tipDetail);
}
// 3. 显示额外内容(IID/响应结果)
if (content) {
const contentWrapper = document.createElement("div");
contentWrapper.style.cssText = `
margin-top: 10px;
`;
const contentLabel = document.createElement("div");
contentLabel.style.cssText = `
font-size: 14px;
margin-bottom: 5px;
font-weight: bold;
`;
contentLabel.textContent = type === "error" ? "校验的IID:" : "响应结果:";
contentWrapper.appendChild(contentLabel);
const contentDisplay = document.createElement("div");
contentDisplay.style.cssText = `
font-size: 13px;
padding: 8px;
background: rgba(255,255,255,0.8);
border-radius: 4px;
white-space: pre-wrap;
line-height: 1.4;
font-family: Consolas, monospace;
`;
// 格式化展示内容
let displayContent = content;
try {
// 如果是JSON字符串,格式化显示
if (type === "success" && typeof content === "object") {
displayContent = JSON.stringify(content, null, 2);
} else if (typeof content === "string" && content.startsWith("{")) {
displayContent = JSON.stringify(JSON.parse(content), null, 2);
}
} catch (e) {
// 非JSON格式则原样显示
displayContent = content;
}
// 超长内容换行处理
if (displayContent.length > 60) {
displayContent = displayContent.match(/.{1,60}/g)?.join('\n') || displayContent;
}
contentDisplay.textContent = displayContent;
contentWrapper.appendChild(contentDisplay);
tipContainer.appendChild(contentWrapper);
}
document.body.appendChild(tipContainer);
// 显示提示框(淡入效果)
setTimeout(() => {
tipContainer.style.opacity = "1";
}, 10);
// 自动隐藏(淡出效果)
setTimeout(() => {
tipContainer.style.opacity = "0";
setTimeout(() => {
tipContainer.remove();
}, 300);
}, duration);
}
/**
* 错误码转中文提示
* @param {object} validateResult - 校验结果对象
* @returns {object} {mainText: string, detailText: string}
*/
function getErrorText(validateResult) {
let mainText = "IID格式不合法";
let detailText = "";
if (validateResult.error === "not_numeric") {
mainText = "⚠️ IID包含非数字字符";
detailText = "IID必须全部由数字组成,不能包含字母、符号或空格";
} else if (validateResult.error === "invalid_length") {
mainText = "⚠️ IID长度不正确";
detailText = `当前长度:${validateResult.length}位,合法长度应为54位或63位`;
} else if (validateResult.failedBlocks && validateResult.failedBlocks.length > 0) {
mainText = `⚠️ IID不合法,有${validateResult.failedBlocks.length}个区块校验失败`;
const failedBlockStr = validateResult.failedBlocks.map(block =>
`第${block.index}区块 (${block.value})`
).join("、");
detailText = `失败的区块:${failedBlockStr}(区块校验位计算错误)`;
}
return { mainText, detailText };
}
/**
* 获取微软激活配置项(改用GM_xmlhttpRequest)
* @returns {Promise<any>} 返回服务器响应的 JSON 数据
*/
async function getGovUrlConfig() {
const url = "https://visualsupport.microsoft.com/api/configuration/govUrlID";
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url: url,
headers: {
"accept": "application/json",
"cache-control": "no-cache"
},
onload: function (response) {
if (response.status >= 200 && response.status < 300) {
try {
resolve(JSON.parse(response.responseText));
} catch (e) {
reject(new Error("解析配置数据失败: " + e.message));
}
} else {
reject(new Error(`HTTP 错误! 状态码: ${response.status}`));
}
},
onerror: function (error) {
reject(new Error("请求配置失败: " + error.message));
}
});
});
}
// 1. Base64URL编码函数(eI):JWT/DPoP标准编码方式
function eI(t) {
let e = t instanceof ArrayBuffer ? new Uint8Array(t) : new TextEncoder().encode(t);
let n = "";
for (let o of e) {
n += String.fromCharCode(o);
}
return btoa(n).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}
// 2. 全局缓存密钥对的变量(单例模式)
let tI = null;
// 3. 生成/获取ECDSA P-256密钥对(yT)
async function yT() {
if (!tI) {
tI = await crypto.subtle.generateKey({
name: "ECDSA",
namedCurve: "P-256"
}, true,
["sign", "verify"]
);
}
return tI;
}
// 4. 核心:生成DPoP令牌(c1e)
async function c1e(t, e) {
try {
const { privateKey: n, publicKey: o } = await yT();
const i = {
alg: "ES256",
typ: "dpop+jwt",
jwk: await crypto.subtle.exportKey("jwk", o)
};
const a = {
htu: t,
htm: e,
jti: crypto.randomUUID(),
iat: Math.floor(Date.now() / 1000)
};
const s = eI(JSON.stringify(i));
const l = eI(JSON.stringify(a));
const u = `${s}.${l}`;
const p = await crypto.subtle.sign({
name: "ECDSA",
hash: "SHA-256"
}, n, new TextEncoder().encode(u));
const g = eI(p);
return `${s}.${l}.${g}`;
} catch (error) {
console.error("生成DPoP令牌失败:", error);
throw error;
}
}
// 生成DPoP令牌
async function testGenerateDPoP() {
const dpopToken = await c1e(
"/api/productActivation/validateIID",
"POST"
);
return dpopToken;
}
//生成x-session-id app_mmsj2c31_x1nrlz06b
function GenerateSessionId() {
const t = Date.now().toString(36);
const e = Math.random().toString(36).substr(2, 9);
return `app_${t}_${e}`;
}
/**
* ✅ 获取 Token JSON 数据(可返回,供全局使用)
* @returns {Promise<Object>}
*/
function getTokenData() {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url: "https://cidtoken.x2ray.cfd",
timeout: 10000,
responseType: "json",
onload: (res) => {
try {
const data = res.response;
if (!data || !data.access_token) {
reject("无效的 Token 数据");
return;
}
resolve(data);
} catch (err) {
reject("解析 JSON 失败:" + err);
}
},
onerror: (err) => reject("网络请求失败:" + err),
ontimeout: () => reject("请求超时")
});
});
}
/**
* 发送激活请求(改用GM_xmlhttpRequest)- 移除内部的IID校验
* @param {string} iid - 从剪贴板获取的IID参数
* @returns {Promise<any>} 响应结果
*/
async function sendActivationRequest(iid) {
if (!iid || iid.trim() === "") {
throw new Error("剪贴板中未获取到有效的IID参数");
}
try {
const dpopToken = await testGenerateDPoP();
const govUrlConfig = await getGovUrlConfig();
const numberOfDigits = Math.floor(iid.length / 9);
const sid = GenerateSessionId();
// ✅ 这里正确获取 token
const tokenJson = await getTokenData();
if (!tokenJson || !tokenJson.access_token) {
throw new Error("获取 AccessToken 失败,请检查网络或接口");
}
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "POST",
url: "https://visualsupport.microsoft.com/api/productActivation/validateIID",
headers: {
"content-type": "application/json",
//"authorization": "Bearer govUrlID",
"authorization": "Bearer " + tokenJson.access_token, // ✅ 已修复
"dpop": dpopToken,
"x-session-id": sid,
"referrer": `https://visualsupport.microsoft.com/${govUrlConfig}/activate`,
},
data: JSON.stringify({
IID: iid,
ProductType: "windows",
productGroup: "Windows",
productName: "Windows 11",
numberOfDigits: numberOfDigits,
Country: "CHN",
Region: "APGC",
InstalledDevices: 1,
OverrideStatusCode: "MUL",
InitialReasonCode: "45164"
}),
onload: function (response) {
if (response.status >= 200 && response.status < 300) {
try {
const result = JSON.parse(response.responseText);
resolve(result);
} catch (e) {
reject(new Error("解析响应数据失败: " + e.message));
}
} else {
reject(new Error(`请求失败! 状态码: ${response.status}, 响应: ${response.responseText}`));
}
},
onerror: function (error) {
reject(new Error("请求发送失败: " + error.message));
}
});
});
} catch (error) {
console.error("请求失败:", error);
throw error;
}
}
/**
* 创建可拖拽的悬浮面板(美化版)
*/
function createFloatPanel() {
// 1. 创建面板容器(美化样式)
const panel = document.createElement("div");
panel.style.cssText = `
position: fixed;
bottom: 20px;
right: 20px;
width: 220px; /* 加宽一点更美观 */
background: rgba(255,255,255,0.95); /* 半透明背景 */
border: 1px solid #e5e7eb;
border-radius: 12px; /* 更大圆角 */
box-shadow: 0 8px 24px rgba(0,0,0,0.12); /* 更柔和的阴影 */
z-index: 999999;
padding: 16px;
transition: background 0.3s, transform 0.2s; /* 过渡动画 */
backdrop-filter: blur(8px); /* 毛玻璃效果 */
cursor: move; /* 提示整个面板可拖拽 */
user-select: none; /* 禁止选中文字 */
`;
panel.id = "ms-activation-panel";
// 2. 创建标题
const panelTitle = document.createElement("div");
panelTitle.style.cssText = `
font-size: 15px;
font-weight: 600;
margin-bottom: 12px;
color: #1f2937;
text-align: center;
padding-bottom: 8px;
border-bottom: 1px solid #f3f4f6; /* 分割线样式 */
`;
panelTitle.textContent = "微软激活ID获取 · 免登录版";
panel.appendChild(panelTitle);
// 3. 创建按钮(美化样式)
const btn = document.createElement("button");
btn.style.cssText = `
width: 100%;
padding: 10px;
background: #0078d4;
color: white;
border: none;
border-radius: 8px;
cursor: pointer; /* 按钮保持点击光标 */
font-size: 14px;
margin-bottom: 10px;
transition: background 0.2s, transform 0.1s; /* 交互动画 */
font-weight: 500;
`;
// 按钮hover/active效果
btn.addEventListener("mouseenter", () => {
btn.style.background = "#0086e5";
});
btn.addEventListener("mouseleave", () => {
btn.style.background = "#0078d4";
});
btn.addEventListener("mousedown", () => {
btn.style.transform = "scale(0.98)";
});
btn.addEventListener("mouseup", () => {
btn.style.transform = "scale(1)";
});
btn.textContent = "获取确认ID";
panel.appendChild(btn);
// 4. 创建状态提示(美化样式)
const status = document.createElement("div");
status.style.cssText = `
font-size: 13px;
color: #4b5563;
text-align: center;
min-height: 18px;
line-height: 1.4;
padding: 4px 0;
border-radius: 6px;
`;
status.textContent = "✅ 就绪";
panel.appendChild(status);
// ===================== 悬浮面板拖拽(PC + Android + 防止出屏) =====================
// 是否正在拖拽
let isDragging = false;
// 鼠标 / 手指 与 面板左上角 的偏移量
let offsetX = 0;
let offsetY = 0;
/**
* 开始拖拽
* @param {number} clientX 鼠标/手指的 X 坐标
* @param {number} clientY 鼠标/手指的 Y 坐标
*/
function startDrag(clientX, clientY) {
// 如果点击的是按钮,不触发拖拽
if (event.target === btn) return;
isDragging = true;
// 获取面板当前在视口中的位置和尺寸
const rect = panel.getBoundingClientRect();
// ★ 关键:将 right/bottom 转换为 left/top,否则拖拽时位置会错乱
panel.style.left = rect.left + "px";
panel.style.top = rect.top + "px";
panel.style.right = "auto";
panel.style.bottom = "auto";
// 计算鼠标 / 手指 与 面板左上角 的偏移量
offsetX = clientX - rect.left;
offsetY = clientY - rect.top;
// 拖动时取消动画,保证跟手
panel.style.transition = "none";
// 拖动时轻微放大,提升交互感
panel.style.transform = "scale(1.02)";
}
/**
* 限制数值在 min ~ max 之间,防止面板被拖出屏幕
*/
function clamp(value, min, max) {
return Math.min(Math.max(value, min), max);
}
/**
* 拖拽移动
* @param {number} clientX
* @param {number} clientY
*/
function moveDrag(clientX, clientY) {
if (!isDragging) return;
// 计算屏幕最大可移动范围
const maxX = window.innerWidth - panel.offsetWidth;
const maxY = window.innerHeight - panel.offsetHeight;
// 计算新位置,并限制在屏幕内
const newLeft = clamp(clientX - offsetX, 0, maxX);
const newTop = clamp(clientY - offsetY, 0, maxY);
// 应用位置
panel.style.left = newLeft + "px";
panel.style.top = newTop + "px";
}
/**
* 结束拖拽
*/
function endDrag() {
if (!isDragging) return;
isDragging = false;
// 恢复过渡动画
panel.style.transition = "background 0.3s, transform 0.2s";
// 恢复缩放
panel.style.transform = "scale(1)";
}
/* ===================== PC 鼠标事件 ===================== */
// 鼠标按下(整个面板监听)
panel.addEventListener("mousedown", (e) => {
e.preventDefault(); // 防止选中文字
startDrag(e.clientX, e.clientY);
});
// 鼠标移动
document.addEventListener("mousemove", (e) => {
moveDrag(e.clientX, e.clientY);
});
// 鼠标松开
document.addEventListener("mouseup", endDrag);
/* ===================== Android 触摸事件 ===================== */
// 手指按下
panel.addEventListener("touchstart", (e) => {
const touch = e.touches[0]; // 第一个触摸点
startDrag(touch.clientX, touch.clientY);
}, { passive: false }); // ★ 必须 passive:false
// 手指移动
document.addEventListener("touchmove", (e) => {
if (!isDragging) return;
e.preventDefault(); // ★ 关键:阻止页面滚动
const touch = e.touches[0];
moveDrag(touch.clientX, touch.clientY);
}, { passive: false });
// 手指松开 / 被打断
document.addEventListener("touchend", endDrag);
document.addEventListener("touchcancel", endDrag);
// ===================== 页面悬浮提示(Toast) =====================
function showToast(message, type = "info", duration = 5000) {
const toast = document.createElement("div");
const colors = {
success: "rgba(40,167,69,0.9)", // 绿
warning: "rgba(255,193,7,0.9)", // 黄
error: "rgba(220,53,69,0.9)", // 红
info: "rgba(0,0,0,0.85)" // 黑
};
toast.textContent = message;
toast.style.cssText = `
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%) translateY(-10px);
background: ${colors[type] || colors.info};
color: #fff;
padding: 10px 16px;
border-radius: 6px;
font-size: 14px;
z-index: 10000;
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
opacity: 0;
transition: opacity 0.3s, transform 0.3s;
pointer-events: none;
white-space: nowrap;
`;
document.body.appendChild(toast);
// 淡入
requestAnimationFrame(() => {
toast.style.opacity = "1";
toast.style.transform = "translateX(-50%) translateY(0)";
});
// 到时间淡出并移除
setTimeout(() => {
toast.style.opacity = "0";
toast.style.transform = "translateX(-50%) translateY(-10px)";
setTimeout(() => toast.remove(), 300);
}, duration);
}
// 6. 按钮点击事件 - 保留原有逻辑,替换提示方式为Toast
btn.addEventListener("click", async () => {
// 定义恢复按钮状态的通用函数
const resetButton = (text = "获取确认ID", statusText = "✅ 就绪") => {
btn.disabled = false;
btn.textContent = text;
status.textContent = statusText;
};
try {
// 禁用按钮防止重复点击
btn.disabled = true;
btn.textContent = "处理中...";
status.textContent = "🔍 读取剪贴板中...";
showToast("正在读取剪贴板内容", "info");
// 从剪贴板获取IID(处理权限拒绝)
let clipboardText;
try {
clipboardText = await navigator.clipboard.readText();
} catch (clipboardError) {
throw new Error("剪贴板访问被拒绝,请允许页面访问剪贴板权限");
}
if (!clipboardText) {
throw new Error("剪贴板为空,请先复制IID内容");
}
const original_iid = clipboardText.trim();
status.textContent = "✅ 校验IID合法性...";
showToast("正在校验IID合法性", "info");
// 修复:兼容旧版JS的空值处理
let aB = t => (t == null ? "" : t.replace(/[^a-zA-Z0-9]/g, "")) || "";
const iid = aB(original_iid);
// 第一步:校验IID合法性
const validateResult = validateIID(iid);
if (!validateResult.valid) {
// 获取错误提示文本
const errorInfo = getErrorText(validateResult);
// 显示精准的错误提示
showFloatTip(errorInfo.mainText, errorInfo.detailText, original_iid);
showToast(errorInfo.mainText, "error");
// 恢复按钮状态
resetButton();
return; // 终止后续流程
}
// IID合法,继续发送请求
status.textContent = "📡 发送请求中...";
showToast("IID验证通过,正在发送请求", "info");
const result = await sendActivationRequest(iid);
// 显示成功提示
showToast("请求成功!结果已复制到剪贴板", "success");
showFloatTip(
"✅ 请求成功!结果已复制到剪贴板",
"响应数据如下,已自动复制到剪贴板",
result,
"success",
5000
);
// 将结果复制到剪贴板
GM_setClipboard(JSON.stringify(result, null, 2), "text");
// 更新状态提示并恢复按钮
resetButton("获取确认ID", "✅ 结果已复制到剪贴板");
// 延迟重置状态(仅成功场景)
setTimeout(() => {
status.textContent = "✅ 就绪";
}, 3000);
} catch (error) {
// 处理所有类型的错误,确保按钮恢复
console.error("操作失败:", error);
// 显示错误提示
showToast(error.message, "error");
showFloatTip(
"❌ 操作失败",
error.message,
"",
"error",
5000
);
// 恢复按钮状态
resetButton("重新获取", `❌ 失败: ${error.message}`);
} finally {
// 仅在错误状态下延迟重置(避免覆盖成功提示)
if (btn.textContent.includes("重新获取")) {
setTimeout(() => {
status.textContent = "✅ 就绪";
}, 5000);
}
}
});
// 7. 将面板添加到页面
document.body.appendChild(panel);
console.info("✅ 微软激活ID获取面板已启用(美化版)");
}
// 页面加载完成后创建悬浮面板
if (document.readyState === "complete" || document.readyState === "interactive") {
createFloatPanel();
} else {
document.addEventListener("DOMContentLoaded", createFloatPanel);
}
})();