thảo luận Hướng dẫn dùng Cloudflare Zero Trust

Thím nào run lúc 6H sáng nay và ngay bây giờ (9H sáng) là được nha
Sáng nay lúc 6H e ngứa tay bấm run thì chạy được
Xong từ 6h30 đến 8H58 là lỗi
9H (Bây giờ) là lại chạy đc :beat_brick:
 
vẫn lỗi thím ơi
Chập chờn vãi
uxby0Nl.gif

1717639612370.png
 
Không rõ nguyên nhân do lỗi hay cf cố ý nhưng mà nếu tăng delay giữa các lần upload list/xóa list lên 2s là chạy ok nhé. Và tất nhiên thời gian chạy workflow cũng tăng lên khá cao, hagezi normal upload cỡ 11 phút.
Vào lib/api.js sửa file này, xóa hết nội dung có sẵn, copy hết đống này vào, rồi bấm commit,
Code:
import { BLOCK_PAGE_ENABLED, LIST_ITEM_SIZE } from "./constants.js";
import { requestGateway } from "./helpers.js";

/**
 * Gets Zero Trust lists.
 *
 * API docs: https://developers.cloudflare.com/api/operations/zero-trust-lists-list-zero-trust-lists
 * @returns {Promise<Object>}
 */
export const getZeroTrustLists = () =>
  requestGateway("/lists", {
    method: "GET",
  });

/**
 * Creates a Zero Trust list.
 *
 * API docs: https://developers.cloudflare.com/api/operations/zero-trust-lists-create-zero-trust-list
 * @param {string} name The name of the list.
 * @param {Object[]} items The domains in the list.
 * @param {string} items[].value The domain of an entry.
 * @returns {Promise}
 */
const createZeroTrustList = (name, items) =>
  requestGateway(`/lists`, {
    method: "POST",
    body: JSON.stringify({
      name,
      type: "DOMAIN",
      items,
    }),
  });

/**
 * Creates Zero Trust lists sequentially.
 * @param {string[]} items The domains.
 */
export const createZeroTrustListsOneByOne = async (items) => {
  let totalListNumber = Math.ceil(items.length / LIST_ITEM_SIZE);

  for (let i = 0, listNumber = 1; i < items.length; i += LIST_ITEM_SIZE) {
    const chunk = items
      .slice(i, i + LIST_ITEM_SIZE)
      .map((item) => ({ value: item }));
    const listName = `CGPS List - Chunk ${listNumber}`;

    try {
      await createZeroTrustList(listName, chunk);
      totalListNumber--;
      listNumber++;
      console.log(`Created "${listName}" list - ${totalListNumber} left`);
      await new Promise(resolve => setTimeout(resolve, 2000));
    } catch (err) {
      console.error(`Could not create "${listName}" - ${err.toString()}`);
      throw err;
    }
  }
};

/**
 * Creates all Zero Trust lists at once.
 * @param {string[]} items The domains.
 */
export const createZeroTrustListsAtOnce = async (items) => {
  const requests = [];

  for (let i = 0, listNumber = 1; i < items.length; i += LIST_ITEM_SIZE) {
    const chunk = items
      .slice(i, i + LIST_ITEM_SIZE)
      .map((item) => ({ value: item }));
    const listName = `CGPS List - Chunk ${listNumber}`;

    requests.push(createZeroTrustList(listName, chunk));
    listNumber++;
  }

  try {
    await Promise.all(requests);
    console.log("Created lists successfully");
  } catch (err) {
    console.error(`Error occurred while creating lists - ${err.toString()}`);
    throw err;
  }
};

/**
 * Deletes a Zero Trust list.
 *
 * API docs: https://developers.cloudflare.com/api/operations/zero-trust-lists-delete-zero-trust-list
 * @param {number} id The ID of the list.
 * @returns {Promise<any>}
 */
const deleteZeroTrustList = (id) =>
  requestGateway(`/lists/${id}`, { method: "DELETE" });

/**
 * Deletes Zero Trust lists sequentially.
 * @param {Object[]} lists The lists to be deleted.
 * @param {number} lists[].id The ID of a list.
 * @param {string} lists[].name The name of a list.
 */
export const deleteZeroTrustListsOneByOne = async (lists) => {
  let totalListNumber = lists.length;

  for (const { id, name } of lists) {
    try {
      await deleteZeroTrustList(id);
      totalListNumber--;
      console.log(`Deleted ${name} list - ${totalListNumber} left`);
      await new Promise(resolve => setTimeout(resolve, 2000));
    } catch (err) {
      console.error(`Could not delete ${name} - ${err.toString()}`);
      throw err;
    }
  }
};

/**
 * Deletes all Zero Trust lists at once.
 * @param {Object[]} lists The lists to be deleted.
 * @param {number} lists[].id The ID of a list.
 * @param {string} lists[].name The name of a list.
 */
export const deleteZeroTrustListsAtOnce = async (lists) => {
  const requests = lists.map(({ id }) => deleteZeroTrustList(id));

  try {
    await Promise.all(requests);
    console.log("Deleted lists successfully");
  } catch (err) {
    console.error(`Error occurred while deleting lists - ${err.toString()}`);
    throw err;
  }
};

/**
 * Gets Zero Trust rules.
 *
 * API docs: https://developers.cloudflare.com/api/operations/zero-trust-gateway-rules-list-zero-trust-gateway-rules
 * @returns {Promise<Object>}
 */
export const getZeroTrustRules = () =>
  requestGateway("/rules", { method: "GET" });

/**
 * Creates a Zero Trust rule.
 *
 * API docs: https://developers.cloudflare.com/api/operations/zero-trust-gateway-rules-create-zero-trust-gateway-rule
 * @param {string} wirefilterExpression The expression to be used for the rule.
 * @param {string} name The name of the rule.
 * @param {string[]} filters The filters to be used for the rule. Default is ["dns"]. Possible values are ["dns", "http", "l4", "egress"].
 * @returns {Promise<Object>}
 */
export const createZeroTrustRule = async (wirefilterExpression, name = "CGPS Filter Lists", filters = ["dns"]) => {
  try {
    await requestGateway("/rules", {
      method: "POST",
      body: JSON.stringify({
        name,
        description:
          "Filter lists created by Cloudflare Gateway Pi-hole Scripts. Avoid editing this rule. Changing the name of this rule will break the script.",
        enabled: true,
        action: "block",
        rule_settings: { "block_page_enabled": BLOCK_PAGE_ENABLED, "block_reason": "Blocked by CGPS, check your filter lists if this was a mistake." },
        filters,
        traffic: wirefilterExpression,
      }),
    });

    console.log("Created rule successfully");
  } catch (err) {
    console.error(`Error occurred while creating rule - ${err.toString()}`);
    throw err;
  }
};

/**
 * Deletes a Zero Trust rule.
 *
 * API docs: https://developers.cloudflare.com/api/operations/zero-trust-gateway-rules-delete-zero-trust-gateway-rule
 * @param {number} id The ID of the rule to be deleted.
 * @returns {Promise<Object>}
 */
export const deleteZeroTrustRule = async (id) => {
  try {
    await requestGateway(`/rules/${id}`, {
      method: "DELETE",
    });

    console.log("Deleted rule successfully");
  } catch (err) {
    console.error(`Error occurred while deleting rule - ${err.toString()}`);
    throw err;
  }
};
File worflow .yml sửa lại mục checkout giống y như vậy. Rồi chạy lại mới workflow (không bấm re-run)

1717643141494.png

Sửa xong chạy thấy chậm quá mà không thấy lỗi thích vọc thì xem dòng 52 và dòng 110
Code:
await new Promise(resolve => setTimeout(resolve, 2000));
Sửa 2000 thành số thấp hơn, 2000 ở đây là 2000 ms, 2000ms = 2s
Chạy 3 lần liên tiếp thành công
1717644657229.png
 
Mà không hiểu sao server VN lởm lắm, mấy trang như dsvn.vn hay của vtvcab không vào được fen ạ, chuyển về HK lại bình thường :D
Do server quản lý các tên miền của VN cùi bắp, hoặc là chặn/bóp băng thông (cdn của vcorp), hoặc có IP mà k chịu trả lời truy vấn (dichvucong.baohiemxahoi.gov.vn), hoặc để server NS k có nghĩa (vov.vn)

Chặn quốc tế https://community.cloudflare.com/t/1-1-1-1-fails-to-resolve-nld-com-vn-at-the-first-attempt/650988

Cả đống máy chủ là chỉ có 1 máy chủ trả lời truy vấn DNSSEC https://dnssec-debugger.verisignlabs.com/dichvucong.baohiemxahoi.gov.vn

Mà lại là tên miền gov.vn nữa chứ https://dnsviz.net/d/dichvucong.baohiemxahoi.gov.vn/dnssec/

Máy chủ NS quản lý thì vô nghĩa/k có thực vov-dns02.?!? https://www.nslookup.io/domains/vov.vn/dns-records/#google
Code:
Question

dig @8.8.8.8 vov.vn. NS

Answer

vov.vn.    894    NS    ns2.xfone.com.vn.
vov.vn.    894    NS    vov-dns02.

Authority

Additional

.    0    OPT     ; payload 512, xrcode 0, version 0, flags 0


Thế đợi thôi à thím
lại chơi trò chặn bóp à bác ... em thấy cứ execute nào quá phút là nó cho chết ngay
hình như sếp trả lời nhầm sang người khác
vấn đề nói ở trên là tạo list trên cloudflare bị lỗi. Người nêu issue có lẽ không phải người Việt
À mình quote nhầm thím ở trên
 
Do server quản lý các tên miền của VN cùi bắp, hoặc là chặn/bóp băng thông (cdn của vcorp), hoặc có IP mà k chịu trả lời truy vấn (dichvucong.baohiemxahoi.gov.vn), hoặc để server NS k có nghĩa (vov.vn)

Chặn quốc tế https://community.cloudflare.com/t/1-1-1-1-fails-to-resolve-nld-com-vn-at-the-first-attempt/650988

Cả đống máy chủ là chỉ có 1 máy chủ trả lời truy vấn DNSSEC https://dnssec-debugger.verisignlabs.com/dichvucong.baohiemxahoi.gov.vn

Mà lại là tên miền gov.vn nữa chứ https://dnsviz.net/d/dichvucong.baohiemxahoi.gov.vn/dnssec/

Máy chủ NS quản lý thì vô nghĩa/k có thực vov-dns02.?!? https://www.nslookup.io/domains/vov.vn/dns-records/#google
Code:
Question

dig @8.8.8.8 vov.vn. NS

Answer

vov.vn.    894    NS    ns2.xfone.com.vn.
vov.vn.    894    NS    vov-dns02.

Authority

Additional

.    0    OPT     ; payload 512, xrcode 0, version 0, flags 0





À mình quote nhầm thím ở trên
Cảm ơn fen nhiều, trả lời chi tiết quá :p
Lại về NextDNS thôi.
 
Không rõ nguyên nhân do lỗi hay cf cố ý nhưng mà nếu tăng delay giữa các lần upload list/xóa list lên 2s là chạy ok nhé. Và tất nhiên thời gian chạy workflow cũng tăng lên khá cao, hagezi normal upload cỡ 11 phút.
Vào lib/api.js sửa file này, xóa hết nội dung có sẵn, copy hết đống này vào, rồi bấm commit,
Code:
import { BLOCK_PAGE_ENABLED, LIST_ITEM_SIZE } from "./constants.js";
import { requestGateway } from "./helpers.js";

/**
 * Gets Zero Trust lists.
 *
 * API docs: https://developers.cloudflare.com/api/operations/zero-trust-lists-list-zero-trust-lists
 * @returns {Promise<Object>}
 */
export const getZeroTrustLists = () =>
  requestGateway("/lists", {
    method: "GET",
  });

/**
 * Creates a Zero Trust list.
 *
 * API docs: https://developers.cloudflare.com/api/operations/zero-trust-lists-create-zero-trust-list
 * @param {string} name The name of the list.
 * @param {Object[]} items The domains in the list.
 * @param {string} items[].value The domain of an entry.
 * @returns {Promise}
 */
const createZeroTrustList = (name, items) =>
  requestGateway(`/lists`, {
    method: "POST",
    body: JSON.stringify({
      name,
      type: "DOMAIN",
      items,
    }),
  });

/**
 * Creates Zero Trust lists sequentially.
 * @param {string[]} items The domains.
 */
export const createZeroTrustListsOneByOne = async (items) => {
  let totalListNumber = Math.ceil(items.length / LIST_ITEM_SIZE);

  for (let i = 0, listNumber = 1; i < items.length; i += LIST_ITEM_SIZE) {
    const chunk = items
      .slice(i, i + LIST_ITEM_SIZE)
      .map((item) => ({ value: item }));
    const listName = `CGPS List - Chunk ${listNumber}`;

    try {
      await createZeroTrustList(listName, chunk);
      totalListNumber--;
      listNumber++;
      console.log(`Created "${listName}" list - ${totalListNumber} left`);
      await new Promise(resolve => setTimeout(resolve, 2000));
    } catch (err) {
      console.error(`Could not create "${listName}" - ${err.toString()}`);
      throw err;
    }
  }
};

/**
 * Creates all Zero Trust lists at once.
 * @param {string[]} items The domains.
 */
export const createZeroTrustListsAtOnce = async (items) => {
  const requests = [];

  for (let i = 0, listNumber = 1; i < items.length; i += LIST_ITEM_SIZE) {
    const chunk = items
      .slice(i, i + LIST_ITEM_SIZE)
      .map((item) => ({ value: item }));
    const listName = `CGPS List - Chunk ${listNumber}`;

    requests.push(createZeroTrustList(listName, chunk));
    listNumber++;
  }

  try {
    await Promise.all(requests);
    console.log("Created lists successfully");
  } catch (err) {
    console.error(`Error occurred while creating lists - ${err.toString()}`);
    throw err;
  }
};

/**
 * Deletes a Zero Trust list.
 *
 * API docs: https://developers.cloudflare.com/api/operations/zero-trust-lists-delete-zero-trust-list
 * @param {number} id The ID of the list.
 * @returns {Promise<any>}
 */
const deleteZeroTrustList = (id) =>
  requestGateway(`/lists/${id}`, { method: "DELETE" });

/**
 * Deletes Zero Trust lists sequentially.
 * @param {Object[]} lists The lists to be deleted.
 * @param {number} lists[].id The ID of a list.
 * @param {string} lists[].name The name of a list.
 */
export const deleteZeroTrustListsOneByOne = async (lists) => {
  let totalListNumber = lists.length;

  for (const { id, name } of lists) {
    try {
      await deleteZeroTrustList(id);
      totalListNumber--;
      console.log(`Deleted ${name} list - ${totalListNumber} left`);
      await new Promise(resolve => setTimeout(resolve, 2000));
    } catch (err) {
      console.error(`Could not delete ${name} - ${err.toString()}`);
      throw err;
    }
  }
};

/**
 * Deletes all Zero Trust lists at once.
 * @param {Object[]} lists The lists to be deleted.
 * @param {number} lists[].id The ID of a list.
 * @param {string} lists[].name The name of a list.
 */
export const deleteZeroTrustListsAtOnce = async (lists) => {
  const requests = lists.map(({ id }) => deleteZeroTrustList(id));

  try {
    await Promise.all(requests);
    console.log("Deleted lists successfully");
  } catch (err) {
    console.error(`Error occurred while deleting lists - ${err.toString()}`);
    throw err;
  }
};

/**
 * Gets Zero Trust rules.
 *
 * API docs: https://developers.cloudflare.com/api/operations/zero-trust-gateway-rules-list-zero-trust-gateway-rules
 * @returns {Promise<Object>}
 */
export const getZeroTrustRules = () =>
  requestGateway("/rules", { method: "GET" });

/**
 * Creates a Zero Trust rule.
 *
 * API docs: https://developers.cloudflare.com/api/operations/zero-trust-gateway-rules-create-zero-trust-gateway-rule
 * @param {string} wirefilterExpression The expression to be used for the rule.
 * @param {string} name The name of the rule.
 * @param {string[]} filters The filters to be used for the rule. Default is ["dns"]. Possible values are ["dns", "http", "l4", "egress"].
 * @returns {Promise<Object>}
 */
export const createZeroTrustRule = async (wirefilterExpression, name = "CGPS Filter Lists", filters = ["dns"]) => {
  try {
    await requestGateway("/rules", {
      method: "POST",
      body: JSON.stringify({
        name,
        description:
          "Filter lists created by Cloudflare Gateway Pi-hole Scripts. Avoid editing this rule. Changing the name of this rule will break the script.",
        enabled: true,
        action: "block",
        rule_settings: { "block_page_enabled": BLOCK_PAGE_ENABLED, "block_reason": "Blocked by CGPS, check your filter lists if this was a mistake." },
        filters,
        traffic: wirefilterExpression,
      }),
    });

    console.log("Created rule successfully");
  } catch (err) {
    console.error(`Error occurred while creating rule - ${err.toString()}`);
    throw err;
  }
};

/**
 * Deletes a Zero Trust rule.
 *
 * API docs: https://developers.cloudflare.com/api/operations/zero-trust-gateway-rules-delete-zero-trust-gateway-rule
 * @param {number} id The ID of the rule to be deleted.
 * @returns {Promise<Object>}
 */
export const deleteZeroTrustRule = async (id) => {
  try {
    await requestGateway(`/rules/${id}`, {
      method: "DELETE",
    });

    console.log("Deleted rule successfully");
  } catch (err) {
    console.error(`Error occurred while deleting rule - ${err.toString()}`);
    throw err;
  }
};
File worflow .yml sửa lại mục checkout giống y như vậy. Rồi chạy lại mới workflow (không bấm re-run)

View attachment 2532042
Sửa xong chạy thấy chậm quá mà không thấy lỗi thích vọc thì xem dòng 52 và dòng 110
Code:
await new Promise(resolve => setTimeout(resolve, 2000));
Sửa 2000 thành số thấp hơn, 2000 ở đây là 2000 ms, 2000ms = 2s
Chạy 3 lần liên tiếp thành công
View attachment 2532128
Update thêm một cách khác để chữa cháy, đó là liên tục request nhét vào mồm thằng cf nếu nó lỗi, chừng nào chạy đc thì thôi. Ưu điểm là mốt cf nó sửa lại hết giới hạn thì lại tự chạy nhanh lại, và tiết kiệm thời gian chạy xuống một chút hagezi normal khoảng tầm 8p.
:shame:
Ai đã làm như quote trên rồi hoặc đã sync fork bản mới nhất của repo gốc thì vào đây
Copy paste vào file lib/api.js

Sau đó copy paste đè toàn bộ nội dung file lib/helpers.js rồi bấm commit
Code:
import {
  ACCOUNT_EMAIL,
  ACCOUNT_ID,
  API_HOST,
  API_KEY,
  API_TOKEN,
} from "./constants.js";

if (!globalThis.fetch) {
  console.warn(
    "\nIMPORTANT: Your Node.js version doesn't have native fetch support and may not be supported in the future. Please update to v18 or later.\n"
  );
  // Advise what to do if running in GitHub Actions
  if (process.env.GITHUB_WORKSPACE)
    console.warn(
      "Since you're running in GitHub Actions, you should update your Actions workflow configuration to use Node v18 or higher."
    );
  // Import node-fetch since there's no native fetch in this environment
  globalThis.fetch = (await import("node-fetch")).default;
}

/**
 * Sends a message to a Discord-compatible webhook.
 * @param {url|string} url The webhook URL.
 * @param {string} message The message to be sent.
 * @returns {Promise}
 */
async function sendMessageToWebhook(url, message) {
  // Create the payload object with the message
  // The message is provided as 2 different properties to improve compatibility with webhook servers outside Discord
  const payload = { content: message, body: message };

  // Send a POST request to the webhook url with the payload as JSON
  try {
    const response = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload),
    });

    // Check if the request was successful
    if (!response.ok) {
      throw new Error(`HTTP error! Status: ${response.status}`);
    } else {
      return true;
    }
  } catch (error) {
    console.error('Error sending message to webhook:', error);
    return false;
  }
}

/**
 * Sends a CGPS notification to a Discord-compatible webhook.
 * Automatically checks if the webhook URL exists.
 * @param {string} msg The message to be sent.
 * @returns {Promise}
 */
export async function notifyWebhook(msg) {
  // Check if the webhook URL exists
  const webhook_url = process.env.DISCORD_WEBHOOK_URL;

  if (webhook_url && webhook_url.startsWith('http')) {
    // Send the message to the webhook
    try {
      await sendMessageToWebhook(webhook_url, `CGPS: ${msg}`);
    } catch (e) {
      console.error('Error sending message to Discord webhook:', e);
    }
  }
  // Not logging the lack of a webhook URL since it's not a feature everyone would use
}

/**
 * Fires request to the specified URL.
 * @param {string} url The URL to which the request will be fired.
 * @param {RequestInit} options The options to be passed to `fetch`.
 * @returns {Promise}
 */
const request = async (url, options) => {
  if (!(API_TOKEN || API_KEY) || !ACCOUNT_ID) {
    throw new Error(
      "The following secrets are required: CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID"
    );
  }

  const headers = API_TOKEN
    ? {
        Authorization: `Bearer ${API_TOKEN}`,
        "Content-Type": "application/json",
      }
    : {
        Authorization: `Bearer ${API_KEY}`,
        "Content-Type": "application/json",
        "X-Auth-Email": ACCOUNT_EMAIL,
        "X-Auth-Key": API_KEY,
      };

  const wait = (ms) => new Promise(resolve => setTimeout(resolve, ms));

  let response;
  let data;
  let attempts = 0;

  while(attempts < 50) {
    try {
      response = await fetch(url, {
        ...options,
        headers: {
          ...options.headers,
          ...headers,
        },
      });

      data = await response.json();

      if (!response.ok) {
        throw new Error('Response not OK');
      }
      return data;
    } catch (error) {
      attempts++;
      if(attempts >= 50) {
        // Send a message to the Discord webhook if it exists
        await notifyWebhook(`An HTTP error has occurred (${response.status}) while making a web request. Please check the logs for further details.`);
        throw new Error(`HTTP error! Status: ${response.status} - ${ 'errors' in data ? data.errors[0].message : JSON.stringify(data) }`);
      }
      await wait(5000);
    }
  }
};

/**
 * Fires request to the Zero Trust gateway.
 * @param {string} path The path which will be appended to the request URL.
 * @param {RequestInit} options The options to be passed to `fetch`.
 * @returns {Promise}
 */
export const requestGateway = (path, options) =>
  request(`${API_HOST}/accounts/${ACCOUNT_ID}/gateway${path}`, options);

/**
 * Normalizes a domain.
 * @param {string} value The value to be normalized.
 * @param {boolean} isAllowlisting Whether the value is to be allowlisted.
 * @returns {string}
 */
export const normalizeDomain = (value, isAllowlisting) => {
  const normalized = value
    .replace(/(0\.0\.0\.0|127\.0\.0\.1|::1|::)\s+/, "")
    .replace("||", "")
    .replace("^$important", "")
    .replace("*.", "")
    .replace("^", "");

  if (isAllowlisting) return normalized.replace("@@||", "");

  return normalized;
};
Sau đó nhớ sửa file .yml workflow mục checkout giống y như vậy
1717735667411.png
 
Back
Top