返回首頁 

Greasy Fork is available in English.

Steam 令牌验证器

支持自动填写 Steam 令牌验证码和批量确认交易与市场

Dette script bør ikke installeres direkte. Det er et bibliotek, som andre scripts kan inkludere med metadirektivet // @require https://update.greasyfork.org/scripts/469857/1218043/Steam%20%E4%BB%A4%E7%89%8C%E9%AA%8C%E8%AF%81%E5%99%A8.js

  1. // ==UserScript==// @name Steam 令牌验证器// @namespace https://keylol.com/t652195-1-1// @version 0.8.3// @description 支持自动填写 Steam 令牌验证码和批量确认交易与市场// @author wave// @match http*://store.steampowered.com/*// @match http*://help.steampowered.com/*// @match http*://checkout.steampowered.com/*// @match http*://steamcommunity.com/*// @exclude http*://store.steampowered.com/login/transfer// @exclude http*://help.steampowered.com/login/transfer// @exclude http*://steamcommunity.com/login/transfer// @exclude http*://store.steampowered.com/login/logout/// @exclude http*://help.steampowered.com/login/logout/// @exclude http*://steamcommunity.com/login/logout/// @exclude http*://store.steampowered.com/widget/*// @grant GM_setValue// @grant GM_getValue// @grant GM_setClipboard// @grant GM_addStyle// @grant GM_addValueChangeListener// @grant GM_xmlhttpRequest// @grant unsafeWindow// @connect steampowered.com// @connect steamcommunity.com// @require https://bundle.run/buffer@6.0.3// @require https://cdn.jsdelivr.net/npm/crypto-js@4.0.0/crypto-js.min.js// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAQAAAAAYLlVAAAFP0lEQVR4AdXXA5Ar2R7H8bMuPdtmnH/Gnr22bdu2bdu27bvewfO7tu2Mvw+pqene5EbTefj8ytUn9TtK0ip07p9tad5hTb2PK9xMdke7Y93pLypdaXii78KdZfmyirQL5m6r056ZsCO6OLFhoeLNMdNzfq4ihS+PnRH/yo74iZX0e3PbR2QlHsTUybIgQcRKt818RRnrYmKZSw4kyNho8vGTrynj3P91+fMOJITYaH3IsI3gy60Oa3dee/D+Fd+nwsLEScoYszpafHx82cfNjnRd2XFSx8md1jX6INlt9XomOj+rjCo998/K3f7i8pa/Oqez+ydK496vxk9LfuxEv0JNTxiwDTPGW764u0ee+Lzr55IrnnGgf/bDyqXe/2rnhZI4aPgpX3n9VX3/mv7ptjtU6RxPtCGapDy5Eaf82FZXfyTTn7p/qkqj/wJtAStD5wZasabHtNtgZmlNVRr1PxdKEl9w67cqgI3NzZoRdnovU+F78rUyL7QFGnwYxK35Sdor7ZhGp1X4ztmd2g0IcjYNT2oLVLqvwrenvFW3n3MaqCB0X6s9iElFpfiBnt7UoivwaZIKQsde2lFRXLKqcA3uoP0oJ+cdKgijW2tH2TjjUuHq3k0/l9umoL47m2jvgYnMWOXHm8oP3lAab6hwoN54I+wChW/kq5IUqODwRoHSjXtDhevM94+nnkopzofJwf3LufQd7ajjqU+/rv4P8UbW98c26tqlc7fSp3un6TXOf1mFYom5+l7BhMWQmDGRkFNvUcY3g5x774ZS6EQMjp3E69MsKrAh6Q4kInGSeOvU95R/vJt2WQg1iYxiH9lc5Y8cZBJpiM84qLEB/5dyVD0zElJiWchL9PLZQDLiIy4y/K9BrcWhbUBlLuDbLRohXjEzsKnyp+YxIfhU4h4ef2MaTahNYyaSicdLGvo4B6kDlD/VPxaCTRRnAMhlBC5Ek548BeAmSd7jjCswBYB8WiEIVZnLNpZQF0GowzMA1kSuQBQPAZiC4GQBRRTbQhRCXwDySI5UgXYAPCAKYSp6GxCEvwEwKlIFFgGwFiGBHPSKqIgwG4CtkSqwD4DxCB3xNg6hLQAfRKpANgBDEYbibRZCUwAyIlNgMh6zEWrjrTvCAACORKJAYwrxOIkg/AW920QjbAJgqfEFErhGsUKqI9ThCSXyaI2QyksAWhpdwMl+tDKIQqjCEfKAAj6knuapi4jRBbyP3AGiEYR4KlH8tbMCj55GFogihtq48XaW9ppfg6Zk4LEdCb1AXaIQr9RkI1cp4vXusodd7OIqxU4QFU6BPB6yjQGkIHgSzVpCVcg8XEg4BXLwKCCDedQljgw8LrKV1RzmBf49ZwvVECT8Alp5ANyns+YaLsSXx0xnII2JQxAjCmjl8inzKDkfAwC9zymHaGJgAa37rCMNQdhKiSKmIUgkC2hdJg6hKsWu0hgxrsAqLhPIBAThHgA7iUOMLCC4qMxkTpLD6yxHcHEOuIYgRhcoThz98W0QgosnwOeRLCBE8RK4zSROkqs57y6ERgCsimwBYScAPRAS6MR6jjEWz1X8AIAWRheos9uJaFKbIuApdRFdFgKQEcZLeu1eyp96E+2ILgsAyGEayQiCi3qcBOAV1UMuYGJOWeXPHrPNa9A2PPI4RzY38XhJWyTkpN07/57yhzdqbXN4DRvFU/Qywpi9YKFjVxXIX7+e8nfvCgmM5SAXuU0Wm2iJhBEbdXfxhgrsk+9U/MCCEzEwDqw0WcA7Kji8MaROtd3vP4xyiwGJcZe7WmPFshjfs/8Hvxyu95jGcTAAAAAASUVORK5CYII=// ==/UserScript==(function() {function bufferizeSecret(secret) {if (typeof secret === 'string') {// Check if it's hexif (secret.match(/[0-9a-f]{40}/i)) {return buffer.Buffer.from(secret, 'hex');} else {// Looks like it's base64return buffer.Buffer.from(secret, 'base64');}}return secret;}function generateAuthCode(secret, timeOffset) {secret = bufferizeSecret(secret);let time = Math.floor(Date.now() / 1000) + (timeOffset || 0);let b = buffer.Buffer.allocUnsafe(8);b.writeUInt32BE(0, 0); // This will stop working in 2038!b.writeUInt32BE(Math.floor(time / 30), 4);let hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA1, CryptoJS.lib.WordArray.create(secret));hmac = buffer.Buffer.from(hmac.update(CryptoJS.lib.WordArray.create(b)).finalize().toString(CryptoJS.enc.Hex), 'hex');let start = hmac[19] & 0x0F;hmac = hmac.slice(start, start + 4);let fullcode = hmac.readUInt32BE(0) & 0x7FFFFFFF;const chars = '23456789BCDFGHJKMNPQRTVWXY';let code = '';for (let i = 0; i < 5; i++) {code += chars.charAt(fullcode % chars.length);fullcode /= chars.length;}return code;}function generateConfirmationKey(identitySecret, time, tag) {identitySecret = bufferizeSecret(identitySecret);let dataLen = 8;if (tag) {if (tag.length > 32) {dataLen += 32;} else {dataLen += tag.length;}}let b = buffer.Buffer.allocUnsafe(dataLen);b.writeUInt32BE(0, 0);b.writeUInt32BE(time, 4);if (tag) {b.write(tag, 8);}let hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA1, CryptoJS.lib.WordArray.create(identitySecret));return hmac.update(CryptoJS.lib.WordArray.create(b)).finalize().toString(CryptoJS.enc.Base64);}function getDeviceID(steamID) {let salt = '';return "android:" + CryptoJS.SHA1(steamID.toString() + salt).toString(CryptoJS.enc.Hex).replace(/^([0-9a-f]{8})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{4})([0-9a-f]{12}).*$/, '$1-$2-$3-$4-$5');}function generateConfirmationQueryParams(account, tag, timeOffset) {var time = Math.floor(Date.now() / 1000) + (timeOffset || 0);var key = generateConfirmationKey(account.identitySecret, time, tag);var deviceID = getDeviceID(account.steamID);return 'a=' + account.steamID + '&tag=' + tag + '&l=schinese&m=react&t=' + time + '&p=' + encodeURIComponent(deviceID) + '&k=' + encodeURIComponent(key);}function showAddAccountDialog(strTitle, strOKButton, strCancelButton, rgModalParams) {if (!strOKButton) {strOKButton = '确定';}if (!strCancelButton) {strCancelButton = '取消';}var $Body = $J('<form/>');var $AccountNameInput = $J('<input/>', {type: 'text', 'class': ''});var $SharedSecretInput = $J('<input/>', {type: 'text', 'class': ''});var $SteamIDInput = $J('<input/>', {type: 'text', 'class': ''});var $IdentitySecretInput = $J('<input/>', {type: 'text', 'class': ''});if (rgModalParams && rgModalParams.inputMaxSize) {$AccountNameInput.attr('maxlength', rgModalParams.inputMaxSize);$SharedSecretInput.attr('maxlength', rgModalParams.inputMaxSize);$SteamIDInput.attr('maxlength', rgModalParams.inputMaxSize);$IdentitySecretInput.attr('maxlength', rgModalParams.inputMaxSize);}$Body.append($J('<div/>', {'class': 'newmodal_prompt_description'}).append('Steam 帐户名称<span data-tooltip-text="非个人资料名称,用于自动填写 Steam 令牌验证码。"> (?)</span>'));$Body.append($J('<div/>', {'class': 'newmodal_prompt_input gray_bevel for_text_input fullwidth'}).append($AccountNameInput));$Body.append($J('<div/>', {'class': 'newmodal_prompt_description', 'style': 'margin-top: 8px;'}).append('共享密钥<span data-tooltip-text="即 shared secret,用于生成 Steam 令牌验证码。"> (?)</span>'));$Body.append($J('<div/>', {'class': 'newmodal_prompt_input gray_bevel for_text_input fullwidth'}).append($SharedSecretInput));$Body.append($J('<div/>', {'class': 'newmodal_prompt_description', 'style': 'margin-top: 8px;'}).append('64 位 Steam ID<span data-tooltip-text="以“7656”开头的 17 位数字,用于确认交易与市场。"> (?)</span>'));$Body.append($J('<div/>', {'class': 'newmodal_prompt_input gray_bevel for_text_input fullwidth'}).append($SteamIDInput));$Body.append($J('<div/>', {'class': 'newmodal_prompt_description', 'style': 'margin-top: 8px;'}).append('身份密钥<span data-tooltip-text="即 identity secret,用于确认交易与市场。"> (?)</span>'));$Body.append($J('<div/>', {'class': 'newmodal_prompt_input gray_bevel for_text_input fullwidth'}).append($IdentitySecretInput));var deferred = new jQuery.Deferred();var fnOK = function() {var name = $AccountNameInput.val().trim();var secret = $SharedSecretInput.val().trim();var steamID = $SteamIDInput.val().trim();var identitySecret = $IdentitySecretInput.val().trim();if (!name) {name = '无名氏';}if (!secret) {ShowAlertDialog('错误', '请输入有效的共享密钥。', '确定');return;}if (steamID && steamID.indexOf('7656') != 0 && steamID.length != 17) {ShowAlertDialog('错误', '请输入有效的 64 位 Steam ID。', '确定');return;}deferred.resolve(name, secret, steamID, identitySecret);};var fnCancel = function() {deferred.reject();};$Body.submit(function(event) {event.preventDefault();fnOK();});var $OKButton = _BuildDialogButton(strOKButton, true);$OKButton.click(fnOK);var $CancelButton = _BuildDialogButton(strCancelButton);$CancelButton.click(fnCancel);var Modal = _BuildDialog(strTitle, $Body, [$OKButton, $CancelButton], fnCancel);if(!rgModalParams || !rgModalParams.bNoPromiseDismiss) {deferred.always(function() {Modal.Dismiss();});}Modal.Show();$AccountNameInput.focus();// attach the deferred's events to the modaldeferred.promise(Modal);return Modal;}function showImportAccountDialog(strTitle, strDescription, strOKButton, strCancelButton, textAreaMaxLength) {if (!strOKButton) {strOKButton = '确定';}if (!strCancelButton) {strCancelButton = '取消';}var $Body = $J('<form/>');var $TextArea = $J('<textarea/>', {'class': 'newmodal_prompt_textarea'});$TextArea.attr('placeholder', strDescription);if (textAreaMaxLength) {$TextArea.attr('maxlength', textAreaMaxLength);$TextArea.bind('keyup change', function() {var str = $J(this).val();var mx = parseInt($J(this).attr('maxlength'));if (str.length > mx) {$J(this).val(str.substr(0, mx));return false;}});}$Body.append($J('<div/>', {'class': 'newmodal_prompt_with_textarea gray_bevel fullwidth'}).append($TextArea));var deferred = new jQuery.Deferred();var fnOK = function() {deferred.resolve($TextArea.val());};var fnCancel = function() {deferred.reject();};$Body.submit(function(event) {event.preventDefault();fnOK();});var $OKButton = _BuildDialogButton(strOKButton, true);$OKButton.click(fnOK);var $CancelButton = _BuildDialogButton(strCancelButton);$CancelButton.click(fnCancel);var Modal = _BuildDialog(strTitle, $Body, [$OKButton, $CancelButton], fnCancel);deferred.always(function() {Modal.Dismiss();});Modal.Show();$TextArea.focus();// attach the deferred's events to the modaldeferred.promise(Modal);return Modal;}function showConfirmationDialog(account, confList) {var strOKButton = '全选';var strCancelButton = '关闭';var $Body = $J('<div/>', {'style': 'position: relative; overflow: hidden; padding-bottom: 66px;'});var $MobileconfList = $J('<div/>', {'id': 'mobileconf_list'});$J.each(confList, function(i, v) {var $ConfirmationEntry = $J('<div/>', {'class': 'mobileconf_list_entry', 'id': 'conf' + v.id, 'data-confid': v.id, 'data-key': v.nonce});var $ConfirmationEntryContent = $J('<div/>', {'class': 'mobileconf_list_entry_content'});var $ConfirmationEntryIcon = $J('<div/>', {'class': 'mobileconf_list_entry_icon'}).append('<img src="' + v.icon + '"/>');var $ConfirmationEntryDescription = $J('<div/>', {'class': 'mobileconf_list_entry_description'}).append('<div>' + v.headline + '</div><div>' + v.summary.join('<br/>') + '</div><div>' + v.type_name + ' - ' + new Date(v.creation_time * 1000).toLocaleString() + '</div>');var $ConfirmationEntryCheckbox = $J('<div/>', {'class': 'mobileconf_list_checkbox'}).append($J('<input/>', {'id': 'multiconf_' + v.id, 'data-confid': v.id, 'data-key': v.nonce, 'value': '1', 'type': 'checkbox'}));var $ConfirmationEntrySep = $J('<div/>', {'class': 'mobileconf_list_entry_sep'});$MobileconfList.append($ConfirmationEntry.append($ConfirmationEntryContent.append($ConfirmationEntryIcon, $ConfirmationEntryDescription, $ConfirmationEntryCheckbox), $ConfirmationEntrySep));$ConfirmationEntry.on('click', function() {window.open('https://steamcommunity.com/mobileconf/detailspage/' + v.id + '?' + generateConfirmationQueryParams(account, 'details' + v.id, timeOffset), '_blank', 'height=790,width=600,resize=yes,scrollbars=yes');});$ConfirmationEntryCheckbox.on('click', function(e) {e.stopPropagation();var nChecked = $J('.mobileconf_list_checkbox input:checked').length;var $elButtons = $J('#mobileconf_buttons');if (nChecked > 0) {var $btnCancel = $J('#mobileconf_buttons .mobileconf_button_cancel');var $btnAccept = $J('#mobileconf_buttons .mobileconf_button_accept');$btnCancel.unbind();$btnAccept.unbind();$btnCancel.text('取消选择');$btnAccept.text('确认已选择');$btnCancel.click(function() {sendMultiMobileConfirmationOp(account, 'cancel', Modal);});$btnAccept.click(function() {sendMultiMobileConfirmationOp(account, 'allow', Modal);});if ($elButtons.is(':hidden')) {$elButtons.css('bottom', -$elButtons.height() + 'px');$elButtons.show();}$elButtons.css('bottom', '0');} else {$elButtons.css('bottom', -$elButtons.height() + 'px');}});});var $MobileconfButtons = $J('<div/>', {'id': 'mobileconf_buttons', 'style': 'display: none;'});var $MobileconfButtonCancel = $J('<div/>', {'class': 'mobileconf_button mobileconf_button_cancel'});var $MobileconfButtonAccept = $J('<div/>', {'class': 'mobileconf_button mobileconf_button_accept'});$MobileconfButtons.append($J('<div/>').append($MobileconfButtonCancel, $MobileconfButtonAccept));$Body.append($MobileconfList, $MobileconfButtons);var deferred = new jQuery.Deferred();var fnOK = function() {$J('.mobileconf_list_checkbox input:not(:checked)').prop('checked', true);$J('.mobileconf_list_checkbox').eq(0).click();};var fnCancel = function() {deferred.reject();};var $OKButton = _BuildDialogButton(strOKButton, true);$OKButton.click(fnOK);var $CancelButton = _BuildDialogButton(strCancelButton);$CancelButton.click(fnCancel);var Modal = _BuildDialog('确认交易与市场', $Body, [$OKButton, $CancelButton], fnCancel);deferred.always(function() {Modal.Dismiss();});Modal.Show();// attach the deferred's events to the modaldeferred.promise(Modal);return Modal;}function addAccount() {showAddAccountDialog('添加账户', '确定', '取消').done(function(name, secret, steamID, identitySecret) {if (steamID && identitySecret) {accounts.push({name,secret,steamID,identitySecret});GM_setValue('accounts', accounts);ShowAlertDialog('添加账户', '添加成功,该账户支持确认交易与市场。', '确定');} else {accounts.push({name,secret});GM_setValue('accounts', accounts);ShowAlertDialog('添加账户', '添加成功,该账户不支持确认交易与市场。', '确定');}});setupTooltips($J('.newmodal'));}function importAccount() {showImportAccountDialog('导入账户', '将要导入的数据粘贴于此', '确定', '取消').done(function(data) {try {data = JSON.parse(data.replace(/("SteamID":)(\d+)/, '$1"$2"'));var name = data.account_name || '无名氏';var secret = data.shared_secret;var steamID = data.steamid || data.Session && data.Session.SteamID || '';var identitySecret = data.identity_secret;if (!secret) {ShowAlertDialog('错误', '共享密钥不存在,请检查后再试。', '确定').done(function() {importAccount();});return;}if (steamID && identitySecret) {accounts.push({name,secret,steamID,identitySecret});GM_setValue('accounts', accounts);ShowAlertDialog('导入账户', '导入成功,该账户支持确认交易与市场。', '确定');} else {accounts.push({name,secret});GM_setValue('accounts', accounts);ShowAlertDialog('导入账户', '导入成功,该账户不支持确认交易与市场。', '确定');}} catch (err) {ShowAlertDialog('错误', '数据格式有误,请检查后再试。', '确定').done(function() {importAccount();});}});}function deleteAccount(elem) {ShowConfirmDialog('删除账户', '确定删除该账户吗?', '确定', '取消').done(function() {var $Elem = $JFromIDOrElement(elem);if ($Elem.data('id') >= accounts.length) {ShowAlertDialog('错误', '无法删除该账户,请稍后再试。', '确定').done(function() {window.location.reload();});} else {var account = accounts.splice($Elem.data('id'), 1)[0];GM_setValue('accounts', accounts);ShowAlertDialog('删除账户', '删除成功。', '确定');}});}function copyAuthCode(elem) {var $Elem = $JFromIDOrElement(elem);GM_setClipboard(generateAuthCode(accounts[$Elem.data('id')].secret, timeOffset));$Elem.css('width', window.getComputedStyle(elem, null).width).text('复制成功').addClass('copy_success');setTimeout(function() {$Elem.text($Elem.data('name')).removeClass('copy_success');}, 1000);}function refreshAccounts() {$AuthenticatorPopupMenu.empty();$J.each(accounts, function(i, v) {var $AuthenticatorPopupMenuItem = $J('<span/>', {'style': 'display: block; padding: 5px 0 5px 12px; margin-right: 27px; min-width: 50px;', 'data-id': i, 'data-name': v.name, 'data-tooltip-text': '点击复制该账户的验证码'}).append(v.name);var $AuthenticatorDeleteAccount = $J('<span/>', {'class': 'delete_account', 'data-id': i, 'data-tooltip-text': '删除该账户'});$AuthenticatorPopupMenu.append($J('<a/>', {'class': 'popup_menu_item', 'style': 'position: relative; padding: 0;'}).append($AuthenticatorPopupMenuItem, $AuthenticatorDeleteAccount));$AuthenticatorPopupMenuItem.on('click', function() {copyAuthCode(this);});$AuthenticatorDeleteAccount.on('click', function() {deleteAccount(this);});});setupTooltips($AuthenticatorPopupMenu);var $AuthenticatorAddAccount = $J('<a/>', {'class': 'popup_menu_item'}).append('添加账户');$AuthenticatorPopupMenu.append($AuthenticatorAddAccount);$AuthenticatorAddAccount.on('click', function() {addAccount();});var $AuthenticatorImportAccount = $J('<a/>', {'class': 'popup_menu_item'}).append('导入账户');$AuthenticatorPopupMenu.append($AuthenticatorImportAccount);$AuthenticatorImportAccount.on('click', function() {importAccount();});}function createConfirmationLink(steamID) {if (!$AuthenticatorPopupMenu.find('.confirmation').length) {$J.each(accounts, function(i, v) {if (v.steamID && steamID == v.steamID) {var $AuthenticatorConfirmation = $J('<a/>', {'class': 'popup_menu_item confirmation'}).append('确认交易与市场');$AuthenticatorPopupMenu.append($AuthenticatorConfirmation);$AuthenticatorConfirmation.on('click', async function() {var waitDialog = ShowBlockingWaitDialog('确认交易与市场', '正在获取确认信息,请稍候…');try {var res = await new Promise((resolve, reject) => {GM_xmlhttpRequest({method: 'GET',url: 'https://steamcommunity.com/mobileconf/getlist?' + generateConfirmationQueryParams(v, 'conf', timeOffset),responseType: 'json',onload: function(response) {resolve(response.response);},onerror: function(error) {reject(error);}});});if (res && res.success) {if (res.conf && res.conf.length) {showConfirmationDialog(v, res.conf);} else {ShowAlertDialog('确认交易与市场', '您当前没有任何确认信息。', '确定');}} else {ShowAlertDialog('错误', res && res.message || '获取确认信息失败,请稍后再试。', '确定');}} catch (err) {ShowAlertDialog('错误', '获取确认信息失败,请稍后再试。', '确定');}waitDialog.Dismiss();});return false;}});}}async function sendMultiMobileConfirmationOp(account, op, modal) {var $rgChecked = $J('.mobileconf_list_checkbox input:checked');if ($rgChecked.length == 0) {return;}var waitDialog = ShowBlockingWaitDialog('确认交易与市场', '正在执行此操作,请稍候…');var rgConfirmationId = [];var rgConfirmationKey = [];$J.each($rgChecked, function(key) {var $this = $J(this);var nConfirmationId = $this.data('confid');var nConfirmationKey = $this.data('key');rgConfirmationId.push(nConfirmationId);rgConfirmationKey.push(nConfirmationKey);});var queryString = 'op=' + op + '&' + generateConfirmationQueryParams(account, op, timeOffset);for (var i = 0; i < rgConfirmationId.length; i++) {queryString += '&cid[]=' + rgConfirmationId[i];queryString += '&ck[]=' + rgConfirmationKey[i];}try {var res = await new Promise((resolve, reject) => {GM_xmlhttpRequest({method: 'POST',url: 'https://steamcommunity.com/mobileconf/multiajaxop',data: queryString,headers: {'Content-Type': 'application/x-www-form-urlencoded'},responseType: 'json',onload: function(response) {resolve(response.response);},onerror: function(error) {reject(error);}});});if (res && res.success) {for (var j = 0; j < rgConfirmationId.length; j++) {$J('#conf' + rgConfirmationId[j]).remove();}var nChecked = $J('.mobileconf_list_checkbox input:checked').length;var $elButtons = $J('#mobileconf_buttons');if (nChecked == 0) {$elButtons.css('bottom', -$elButtons.height() + 'px');}if ($J('.mobileconf_list_entry').length == 0) {modal && modal.Dismiss();} else {modal && modal.AdjustSizing();}} else {ShowAlertDialog('确认错误', res && res.message || '执行此操作时出现问题。请稍后再重试您的请求。', '确定');}} catch (err) {ShowAlertDialog('确认错误', '执行此操作时出现问题。请稍后再重试您的请求。', '确定');}waitDialog.Dismiss();}function setupTooltips(selector) {if (window.location.hostname == 'store.steampowered.com' || window.location.hostname == 'checkout.steampowered.com') {BindTooltips(selector, {tooltipCSSClass: 'store_tooltip'});} else if (window.location.hostname == 'help.steampowered.com') {BindTooltips(selector, {tooltipCSSClass: 'help_tooltip'});} else if (window.location.hostname == 'steamcommunity.com') {BindTooltips(selector, {tooltipCSSClass: 'community_tooltip'});}}GM_addStyle(`.delete_account {position: absolute;right: 0;top: 0;padding: 5px 7.5px;width: 12px;height: calc(100% - 10px);background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAQAAAD8fJRsAAAAkElEQVR4AXWQxWEDMRBFJ6AWArqGmW7G12HMDN0ZFmr4dqKF00rDPGPhycnr/vi9nJVPl2qI7Dd0WZpZEyFEygKhy1CkPsX4JCLlB6OP6jo3eRHxhh3xA+OBLULedCtExDOGcRvM6DZzpP/RxgtR4fDKat/ylPUKpZwao1A769VBDbls3H5WO6KfjVu5YOVJDkyDcoTnvnKRAAAAAElFTkSuQmCC);background-position: center;background-repeat: no-repeat;background-origin: content-box;cursor: pointer;}.copy_success {color: #57cbde !important;}#mobileconf_list {overflow-y: auto;max-width: 600px;max-height: calc(100vh - 270px);}.mobileconf_list_entry {cursor: default;font-size: 15px;text-shadow: none;width: 100%;-webkit-transition: opacity 0.1s, top 0.4s;transition: opacity 0.1s, top 0.4s;}.mobileconf_list_entry.copy {-webkit-transition: opacity 0.4s, top 0.4s;transition: opacity 0.4s, top 0.4s;}.mobileconf_list_entry_content {display: flex;padding: 10px 20px;}.mobileconf_list_entry_icon {height: 3.5em;margin-right: 10px;}.mobileconf_list_entry_icon > img {width: 32px;}.mobileconf_list_entry_description {flex: 1;min-width: 0;margin-right: 10px;}.mobileconf_list_entry_description > div {color: #7a7a7a;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;}.mobileconf_list_entry_description > div:first-of-type {color: white;}.mobileconf_list_checkbox {overflow: hidden;vertical-align: middle;display: inline-block;color: #ffffff;width: 3em;height: 3em;transform: scale(1.5);transition-property: transform;transition-duration: 0.1s;}.mobileconf_list_checkbox input {width: 3em;height: 3em;}.mobileconf_list_entry_sep {border-top: 1px solid #303030;}#mobileconf_buttons {position: absolute;display: inline-block;vertical-align: middle;height: 3.3em;line-height: 3.3em;width: 100%;font-size: 20px;background: #324056;background-image: radial-gradient(ellipse farthest-corner at 50% 0px,rgb(74, 107, 152) 0%,transparent 50%);bottom: -3em;left: 0;z-index: 10;-webkit-transition-property: bottom;transition-property: bottom;-webkit-transition-duration: 0.4s;transition-duration: 0.4s;}.mobileconf_button {width: 50%;display: inline-block;overflow: hidden;text-align: center;vertical-align: middle;line-height: normal;cursor: pointer;}`);var $GlobalActionMenu = $J('#global_action_menu');var $AuthenticatorLink = $J('<span/>', {'class': 'pulldown global_action_link', 'style': 'display: inline-block; padding-left: 4px; line-height: 25px;', 'onclick': 'ShowMenu(this, "authenticator_dropdown", "right");'}).append('Steam 令牌验证器');var $AuthenticatorDropdown = $J('<div/>', {'class': 'popup_block_new', 'id': 'authenticator_dropdown', 'style': 'display: none;'});var $AuthenticatorPopupMenu = $J('<div/>', {'class': 'popup_body popup_menu'});$GlobalActionMenu.prepend($AuthenticatorDropdown.append($AuthenticatorPopupMenu));$GlobalActionMenu.prepend($AuthenticatorLink);var accounts = GM_getValue('accounts') || [];refreshAccounts();GM_addValueChangeListener('accounts', function(name, old_value, new_value, remote) {accounts = new_value;refreshAccounts();if (userSteamID) {$AuthenticatorPopupMenu.find('.confirmation').remove();createConfirmationLink(userSteamID);}AlignMenu($AuthenticatorLink, 'authenticator_dropdown', 'right');});if (window.location.pathname == '/mobileconf/conf') {let account;$J.each(accounts, function(i, v) {if (v.steamID && g_steamID == v.steamID) {account = v;return false;}});unsafeWindow.GetValueFromLocalURL = function(url, timeout, success, error, fatal) {if (url.indexOf('steammobile://steamguard?op=conftag&arg1=allow') !== -1) {success(generateConfirmationQueryParams(account, 'allow', timeOffset));} else if (url.indexOf('steammobile://steamguard?op=conftag&arg1=cancel') !== -1) {success(generateConfirmationQueryParams(account, 'cancel', timeOffset));} else if (url.indexOf('steammobile://steamguard?op=conftag&arg1=details') !== -1) {success(generateConfirmationQueryParams(account, 'details', timeOffset));}};$J('html').removeClass('force_desktop').addClass('responsive');V_SetCookie('strResponsiveViewPrefs', null, -1);$J('.mobileconf_list_entry').each(function() {var $this = $J(this);if (!$this.has('.mobileconf_list_checkbox').length) {var $ConfirmationEntryCheckbox = $J('<div/>', {'class': 'mobileconf_list_checkbox'}).append($J('<input/>', {'id': 'multiconf_' + $this.data('confid'), 'data-confid': $this.data('confid'), 'data-key': $this.data('key'), 'value': '1', 'type': 'checkbox'}));$this.find('.mobileconf_list_entry_icon').after($ConfirmationEntryCheckbox);$ConfirmationEntryCheckbox.on('click', function(e) {e.stopPropagation();var nChecked = $J('.mobileconf_list_checkbox input:checked').length;var $elButtons = $J('#mobileconf_buttons');if (nChecked > 0) {var $btnCancel = $J('#mobileconf_buttons .mobileconf_button_cancel');var $btnAccept = $J('#mobileconf_buttons .mobileconf_button_accept');$btnCancel.unbind();$btnAccept.unbind();$btnCancel.text('取消选择');$btnAccept.text('确认已选择');$btnCancel.click(function() {ActionForAllSelected('cancel');});$btnAccept.click(function() {ActionForAllSelected('allow');});if ($elButtons.is(':hidden')) {$elButtons.css('bottom', -$elButtons.height() + 'px');$elButtons.show();}$elButtons.css('bottom', '0');} else {$elButtons.css('bottom', -$elButtons.height() + 'px');}});}});var $ResponsiveHeaderContent = $J('.responsive_header_content');var $ConfirmationCheckAll = $J('<div/>', {'class': 'btn_green_steamui btn_medium'}).append('<span>全选</span>');var $ConfirmationRefresh = $J('<div/>', {'class': 'btn_blue_steamui btn_medium'}).append('<span>刷新</span>');$ResponsiveHeaderContent.append($J('<div/>', {'style': 'position: absolute; top: 15px; right: 8px;'}).append($ConfirmationCheckAll, '\n', $ConfirmationRefresh));$ConfirmationCheckAll.on('click', function() {if ($J('#mobileconf_list').is(':visible') && $J('#mobileconf_details').is(':hidden')) {$J('.mobileconf_list_checkbox input:not(:checked)').click();}});$ConfirmationRefresh.on('click', function() {if (account) {window.location.replace('https://steamcommunity.com/mobileconf/conf?' + generateConfirmationQueryParams(account, 'conf', timeOffset));} else {window.location.reload();}});}var intersectionObserver = new IntersectionObserver(function(entries) {if (entries[0].intersectionRatio > 0) {var name = $J('#login_twofactorauth_message_entercode_accountname, [class^="login_SigningInAccountName"], [class^="newlogindialog_AccountName"]').text();$J.each(accounts, function(i, v) {if(name == v.name) {var $AuthCodeInput = $J('#twofactorcode_entry, [class^="login_AuthenticatorInputcontainer"] input.DialogInput, [class^="newlogindialog_SegmentedCharacterInput"] input, [class^="segmentedinputs_SegmentedCharacterInput"] input');var dt = new DataTransfer();dt.setData('text', generateAuthCode(v.secret, timeOffset));$AuthCodeInput[0].dispatchEvent(new ClipboardEvent('paste', {clipboardData: dt, bubbles: true}));return false;}});}});var mutationObserver = new MutationObserver(function() {if ($J('#twofactorcode_entry, [class^="login_AuthenticatorInputcontainer"] input.DialogInput, [class^="newlogindialog_SegmentedCharacterInput"] input, [class^="segmentedinputs_SegmentedCharacterInput"] input').length) {intersectionObserver.observe($J('#twofactorcode_entry, [class^="login_AuthenticatorInputcontainer"] input.DialogInput, [class^="newlogindialog_SegmentedCharacterInput"] input, [class^="segmentedinputs_SegmentedCharacterInput"] input')[0]);}if ($J('[class^="newlogindialog_EnterCodeInsteadLink"] [class^="newlogindialog_TextLink"]').length) {$J('[class^="newlogindialog_EnterCodeInsteadLink"] [class^="newlogindialog_TextLink"]')[0].click();}});var userSteamID;if ($J('#account_dropdown .persona').length) {if (typeof g_steamID != 'undefined' && g_steamID) {userSteamID = g_steamID;createConfirmationLink(userSteamID);} else {GM_xmlhttpRequest({method: 'GET',url: 'https://steamcommunity.com/my/?xml=1',onload: function(response) {if (response.responseXML) {var steamID = $J(response.responseXML).find('steamID64').text();if (steamID) {userSteamID = steamID;createConfirmationLink(userSteamID);}}}});}if (window.location.href.indexOf('checkout.steampowered.com/login/?purchasetype=') !== -1) {mutationObserver.observe(document.body, {childList: true, subtree: true});}} else {mutationObserver.observe(document.body, {childList: true, subtree: true});}var timeOffset = 0;GM_xmlhttpRequest({method: 'POST',url: 'https://api.steampowered.com/ITwoFactorService/QueryTime/v0001',responseType: 'json',onload: function(response) {if (response.response && response.response.response && response.response.response.server_time) {timeOffset = response.response.response.server_time - Math.floor(Date.now() / 1000);}}});})();