Untitled
unknown
plain_text
3 years ago
11 kB
11
Indexable
const clientId = '746239575955-c4d2o1ahg4ts6ahm3a5lh5lp9g8m15h4.apps.googleusercontent.com';
const clientSecret = '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';
const refreshToken = '';
const service_account = true
const service_account_json = {
"type": "service_account",
"project_id": "gcp-web-bill",
"private_key_id": "2ffeb836b95626dc159e7656fa1a4a9b79b986f4",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCT7lBxMBMGXYF4\n4zOTNYDPxSEeHS42ruGRq2u8OvusgJl92WOwvMQpAMC/2v67fZpqKIeC87H9sR7n\nBsbOWX92dF5RQB4kbiZRR2tu9eaK2TAXrKeRdC8dp7Iv/6k0M5wAnkJmOUWLkZYO\nen2xM95HmCcWF3MSgq9kyuqouLL7EBEcFdT6j3lz2wyLEMt4u4h17/NH5kfEdmjF\n+hG/Jk0cAyE/vdcY2m7dH6rG+1utp75Ft9ZQUX/hVzxo5d5Xmmexx4qz63FmzSAh\nHRHi8xxyRuAzIYpbVJzcqlPTp1wqpvF2AE4yKynNBGmcfJz0duG/zndESy2W93xw\nnUUdE5mlAgMBAAECggEACpDBEJB7L19yzZhGmPs/h7df4ed6I0AyzqVkZLV+v6eQ\nrucdomQdC4OpAJrqyifSpUXfRdhTbFff6ea3QMouGx79FIcEkBwI4xG7h9mKvXx9\nHZfAgRg//Dl7tcdoBZkxCW9ENUpeX/VGNyMDAqq+c7UXh5Glr5sDXWrLv0Cv0dQM\nUlnSYjWIaqK2gV+t0DRr21vkZFvDKVTEVQFgWM0T+O736j4u63Ghw0llUs4h7fB9\nMluJx/61LdJShhto750Rj720AS/ZTDSlmXGn5dYO8nBxPO0IAiIklv+IYDZrXMX+\nU6/Lr1VbEUL9zHHfrKxSLLMHVUy5/SurpbGPNqMzSQKBgQDQ/1KMYkSVr//+l1Tx\nkPeXA2OG8djDN0uXZ+SpvLSkWeEXw2VjP9qQ6CHH/j2cR5beuflP4OCZhnDVblum\ns/5uZs42H62T2iXlpR01y2NHFM/OJOKoHu/MkwR6YxmtM6CsuoIdbA/86Qx4R0y/\n2DxvSoB9+07t9sWNq9fgw+1RKQKBgQC1MzFBrLX/Tpa5ArIXk7faUyDDAmgPN9Z8\nxXQ1nWCKD9AI2F+NuUZ2lGkXC4zMj9dpZ9p3F6WrDbc5oQ243I6iDkPSPXsNlGwr\n8epR2DQV7eK44yywRAPcFGz9e2TIiV/uQRzYeub9qE9WXcAiihBer5hhbaAzG13Y\nwzN3A8soHQKBgA6oGS3nJlApC5bbHgXi2LoqbqxkAYOPOSnhC1Qr+68a7oIwHcgc\nDkPjQ5s25TM0ggwUlrtXVejuWLNfDeZe8RTk+Mkq541a2xWDwsym+stdVkVqqMqJ\ngN+j38iFcqOG31m9qqpNjcF6xnkY5vT9QR+85c3v9dUSXUBWMMl+dAIhAoGBAKYW\nWVTQYTW2LFNC1EjmHoRg48u7nfQtA030kxM9wKpr2gzxf4xhQeQZHsZ/0LwEMLet\n+MJmi3ThqouJQxGqIJcMKkBAGFWXMRuKr3P7j6p2FPXRTTn37e3BTzF89CEYQjUZ\nu7310Vq59pa8cgt2r5CKtUrAeDHAKOIx8i9p68JFAoGAfUsqAQgrIDYDMpmSgwo9\nYBALum6m9FjPw3GCqIEPq7WS9rHKe4TWLWT1h9GMJ3j6Tq5GNCvIan9q/k9lmpWS\nJWD8uwgeY5u/EByVlE2sHzFNGWkhUEjJwLPNlOE1hScYfb8b8c3YDixJKVMLvx+G\nV5KDunuVaU5MECrqQW7SoAM=\n-----END PRIVATE KEY-----\n",
"client_email": "gcp-web-billing-hook@gcp-web-bill.iam.gserviceaccount.com",
"client_id": "113565551544602521875",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/gcp-web-billing-hook%40gcp-web-bill.iam.gserviceaccount.com",
"universe_domain": "googleapis.com"
}
var billing_ids = [{
"name": "GCP Main Billing",
"id": "01924B-D2C7F3-5DE8E7"
}
]
const html = `<!DOCTYPE html>
<html>
<head>
<title>GCP Server Current State</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootswatch@4/dist/flatly/bootstrap.min.css">
</head>
<body>
<header>
<nav class="navbar navbar-dark bg-dark navbar-expand-lg">
<a href="/" class="navbar-brand d-flex align-items-center">
<img src="https://images.cdn.hashhackers.com/logo/logo-white-d.svg" class="btn1" width="220" height="40">
</a>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ">
</ul>
</div>
</nav>
</header>
<div class="container mt-5 mb-5">
<marquee>Web services which are inactive need not to be reported, they'll be back online in a time frame of 24 to 48 hours.</marquee>
<ul id="billing-list" class="list-group">
<li class="list-group-item active text-center">Billing Status</li>
<!-- JavaScript code will populate the rest of the list -->
</ul>
</div>
<!-- Bootstrap JavaScript -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.9.3/umd/popper.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/js/bootstrap.min.js"></script>
<script>
const billing_ids = ` + billing_ids.length + `;
const billing_names = ${JSON.stringify(billing_ids.map(billing => billing.name))}
// Generate an array of numbers from 0 to billing_ids - 1
const indexArray = Array.from({ length: billing_ids }, (_, i) => i);
// Loop through the indexArray and send requests to the API endpoint using each number as an index
for (const index of indexArray) {
const listItem = $('<li class="text-wrap">').addClass('list-group-item d-flex justify-content-between align-items-center');
const nameSpan = $('<span class="d-inline-block text-break">').text(billing_names[index]).appendTo(listItem);
const statusSpan = $('<span>').text('Checking...').addClass('badge badge-secondary').appendTo(listItem);
// Send a request to the API endpoint with the current index and set the status badge
$.getJSON('/'+index, (data) => {
if (data.status == 'invalid') {
statusSpan.text('API Error').addClass('badge-info').removeClass('badge-secondary');
} else if (data.status) {
statusSpan.text('Active').addClass('badge-success').removeClass('badge-secondary');
} else {
statusSpan.text('Inactive').addClass('badge-danger').removeClass('badge-secondary');
}
});
$('#billing-list').append(listItem);
}
</script>
</body>
</html>`
async function handleRequest(request) {
let requrl = new URL(request.url);
let path = requrl.pathname;
if (path == '/') {
return new Response(html, {
status: 200,
headers: {
"content-type": "text/html;",
"Access-Control-Allow-Origin": "*",
}
});
}
let billingAccountId = path.slice(1);
const accessToken = await fetchAccessToken();
// Build the API request URL
const url = 'https://cloudbilling.googleapis.com/v1/billingAccounts/' + billing_ids[billingAccountId].id;
// Send the API request to check if the billing account is active
const response = await fetch(url, {
headers: {
Authorization: `Bearer ${accessToken}`
}
});
var text = await response.text()
if (!response.ok) {
return new Response('{"status":"invalid"}', {
status: 200,
headers: {
"content-type": "application/json;",
"Access-Control-Allow-Origin": "*",
}
});
}
const data = JSON.parse(text);;
// Check if the billing account is active
const billingEnabled = data.open;
// Return a response based on whether the billing account is active or not
if (billingEnabled) {
return new Response('{"status":' + billingEnabled + '}', {
status: 200,
headers: {
"content-type": "application/json;",
"Access-Control-Allow-Origin": "*",
}
});
} else {
let json = {
chat_id: "513611281",
text: "Web Service Offline: " + billing_ids[billingAccountId].name,
}
await fetch("https://api.telegram.org/bot929918166:AAFbDTrQZASGrcmyuplm3Sw4ym-dAv4EKac/SendMessage", {
method: "POST",
headers: {
'content-type': 'application/json',
},
body: JSON.stringify(json)
});
return new Response('{"status":' + billingEnabled + '}', {
status: 200,
headers: {
"content-type": "application/json;",
"Access-Control-Allow-Origin": "*",
}
});
}
}
async function fetchAccessToken() {
const url = "https://oauth2.googleapis.com/token";
const headers = {
'Content-Type': 'application/x-www-form-urlencoded'
};
var post_data;
if (service_account) {
console.log('Service Account')
const jwttoken = await JSONWebToken.generateGCPToken(service_account_json);
post_data = {
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
assertion: jwttoken,
};
} else {
console.log('Refresh Token')
post_data = {
client_id: clientId,
client_secret: clientSecret,
refresh_token: refreshToken,
grant_type: "refresh_token",
};
}
let requestOption = {
'method': 'POST',
'headers': headers,
'body': await enQuery(post_data)
};
let response;
for (let i = 0; i < 3; i++) {
response = await fetch(url, requestOption);
if (response.ok) {
break;
}
await this.sleep(800 * (i + 1));
}
const data = await response.json();
return data.access_token;
}
const JSONWebToken = {
header: {
alg: 'RS256',
typ: 'JWT'
},
importKey: async function(pemKey) {
var pemDER = this.textUtils.base64ToArrayBuffer(pemKey.split('\n').map(s => s.trim()).filter(l => l.length && !l.startsWith('---')).join(''));
return crypto.subtle.importKey('pkcs8', pemDER, {
name: 'RSASSA-PKCS1-v1_5',
hash: 'SHA-256'
}, false, ['sign']);
},
createSignature: async function(text, key) {
const textBuffer = this.textUtils.stringToArrayBuffer(text);
return crypto.subtle.sign('RSASSA-PKCS1-v1_5', key, textBuffer)
},
generateGCPToken: async function(serviceAccount) {
const iat = parseInt(Date.now() / 1000);
var payload = {
"iss": serviceAccount.client_email,
"scope": "https://www.googleapis.com/auth/cloud-billing",
"aud": "https://oauth2.googleapis.com/token",
"exp": iat + 3600,
"iat": iat
};
const encPayload = btoa(JSON.stringify(payload));
const encHeader = btoa(JSON.stringify(this.header));
var key = await this.importKey(serviceAccount.private_key);
var signed = await this.createSignature(encHeader + "." + encPayload, key);
return encHeader + "." + encPayload + "." + this.textUtils.arrayBufferToBase64(signed).replace(/\//g, '_').replace(/\+/g, '-');
},
textUtils: {
base64ToArrayBuffer: function(base64) {
var binary_string = atob(base64);
var len = binary_string.length;
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes.buffer;
},
stringToArrayBuffer: function(str) {
var len = str.length;
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
bytes[i] = str.charCodeAt(i);
}
return bytes.buffer;
},
arrayBufferToBase64: function(buffer) {
let binary = '';
let bytes = new Uint8Array(buffer);
let len = bytes.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return btoa(binary);
}
}
};
function enQuery(data) {
const ret = [];
for (let d in data) {
ret.push(encodeURIComponent(d) + '=' + encodeURIComponent(data[d]));
}
return ret.join('&');
}
function sleep(ms) {
return new Promise(function(resolve, reject) {
let i = 0;
setTimeout(function() {
//console.log('sleep' + ms);
i++;
if (i >= 2) reject(new Error('i>=2'));
else resolve(i);
}, ms);
})
}
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})Editor is loading...