← 返回 TimeAmber
1115日  10:58:45   星期五

网络剪贴板详情

网络剪贴板(netcut.cn)是一款极简的提供跨平台的文本复制粘贴和全格式文件传送的在线工具,操作简单,让数据传送更简单。

网络剪贴板可以用于数据临时存储,文本分享,文件分享,不同设备文件和文本传送,网络便签,文本去格式化编辑工具等用途。

剪贴板文本 文件( 1 个 )
addEventListener('fetch', event => {
  event.respondWith(processRequest(event.request));
});

async function processRequest(request) {
  const requestUrl = new URL(request.url);

  if (request.method === 'GET' && requestUrl.pathname === '/') {
    return new Response(generateHTMLForm(), {
      headers: {
        'Content-Type': 'text/html;charset=UTF-8',
        ...securityHeaders,
      },
    });
  }

  if (request.method === 'POST' && requestUrl.pathname === '/send') {
    try {
      const formData = await request.formData();

      // 验证并清理服务器 URL
      let apiServerUrl;
      try {
        apiServerUrl = sanitizeApiServerUrl(formData.get('server') || 'https://api.day.app');
      } catch (error) {
        return new Response(
          `<div class="notification error">无效的服务器 URL,请输入正确的 HTTPS 地址。</div><a href="/">返回</a>`,
          {
            headers: {
              'Content-Type': 'text/html;charset=UTF-8',
              ...securityHeaders,
            },
          }
        );
      }

      const apiKey = formData.get('key');
      const notificationTitle = formData.get('title') || '';
      const notificationBody = formData.get('body') || '';

      let apiPath = `/${encodeURIComponent(apiKey)}`;
      if (notificationTitle) {
        apiPath += `/${encodeURIComponent(notificationTitle)}`;
      }
      apiPath += `/${encodeURIComponent(notificationBody)}`;

      const queryParams = new URLSearchParams();
      const shouldArchive = formData.get('isArchive') === '1';

      ['level', 'sound', 'icon', 'group', 'badge', 'url', 'copy', 'autocopy'].forEach(param => {
        const value = formData.get(param);
        if (value) queryParams.append(param, value);
      });

      const completeApiUrl = `${apiServerUrl}${apiPath}?${queryParams.toString()}`;

      let apiResponse;
      const requestMethod = (formData.get('method') || 'GET').toUpperCase();

      // 验证请求方法
      if (requestMethod !== 'GET' && requestMethod !== 'POST') {
        return new Response('无效的请求方法', { status: 400 });
      }

      if (requestMethod === 'POST') {
        const postData = {
          title: notificationTitle,
          body: notificationBody,
        };
        if (shouldArchive) {
          postData.isArchive = '1';
        } else {
          postData.isArchive = '2';
        }
        ['level', 'sound', 'icon', 'group', 'badge', 'url', 'copy', 'autocopy'].forEach(param => {
          const value = formData.get(param);
          if (value) postData[param] = value;
        });

        apiResponse = await fetch(`${apiServerUrl}/${encodeURIComponent(apiKey)}`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(postData),
        });
      } else {
        
        if (shouldArchive) {
          queryParams.append('isArchive', '1');
        } else {
          queryParams.append('isArchive', '2');
        }

        apiResponse = await fetch(completeApiUrl, { method: 'GET' });
      }

      if (apiResponse.ok) {
        return new Response(generateSuccessHTML(), {
          headers: {
            'Content-Type': 'text/html;charset=UTF-8',
            ...securityHeaders,
          },
        });
      } else {
        // 避免将详细错误信息暴露给用户
        return new Response(
          `<div class="notification error">推送失败,请稍后重试。</div><a href="/">返回</a>`,
          {
            headers: {
              'Content-Type': 'text/html;charset=UTF-8',
              ...securityHeaders,
            },
          }
        );
      }
    } catch (error) {
      // 可在此记录错误日志,例如 console.error(error);
      return new Response(
        `<div class="notification error">发生未知错误,请稍后重试。</div><a href="/">返回</a>`,
        {
          headers: {
            'Content-Type': 'text/html;charset=UTF-8',
            ...securityHeaders,
          },
        }
      );
    }
  }

  return new Response('Not Found', { status: 404 });
}

function sanitizeApiServerUrl(url) {
  try {
    const parsedUrl = new URL(url);
    if (parsedUrl.protocol !== 'https:') {
      throw new Error('只允许使用 HTTPS 协议的服务器地址');
    }
    return parsedUrl.origin;
  } catch (error) {
    throw new Error('无效的服务器 URL');
  }
}

// 安全头信息
const securityHeaders = {
  'Content-Security-Policy':
    "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'; font-src https://fonts.googleapis.com https://fonts.gstatic.com;",
  'X-Content-Type-Options': 'nosniff',
  'X-Frame-Options': 'DENY',
  'Referrer-Policy': 'no-referrer',
  'Strict-Transport-Security': 'max-age=63072000; includeSubDomains; preload',
};

function generateHTMLForm() {
  return `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Bark Sender</title>
  <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 16 16%22><text y=%2214%22 font-size=%2214%22>⚡</text></svg>">
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
  <style>
    *, *::before, *::after {
      box-sizing: border-box;
    }

    :root {
      --primary-color: #7C3AED;
      --primary-hover-color: #6D28D9;
      --background-color: #F3F4F6;
      --card-background-color: #FFFFFF;
      --text-color: #1F2937;
      --border-color: #E5E7EB;
      --success-color: #10B981;
      --error-color: #EF4444;
    }

    body {
      font-family: 'Inter', sans-serif;
      background-color: var(--background-color);
      color: var(--text-color);
      line-height: 1.5;
      margin: 0;
      padding: 0;
    }

    .container {
      max-width: 600px;
      margin: 2rem auto;
      padding: 2rem;
      background-color: var(--card-background-color);
      border-radius: 0.5rem;
      box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
    }

    h1 {
      font-size: 2.3rem;
      font-weight: 600;
      text-align: center;
      margin-bottom: 1.5rem;
      color: var(--primary-color);
    }

    form {
      display: grid;
      grid-template-columns: 1fr;
      gap: 1rem;
    }

    label {
      font-weight: 500;
      display: block;
      margin-bottom: 0.5rem;
    }

    input[type="text"],
    input[type="url"],
    input[type="number"],
    select,
    textarea {
      width: 100%;
      padding: 0.5rem;
      border: 1px solid var(--border-color);
      border-radius: 0.25rem;
      font-size: 1rem;
      transition: border-color 0.3s ease;
    }

    input[type="text"]:focus,
    input[type="url"]:focus,
    input[type="number"]:focus,
    select:focus,
    textarea:focus {
      outline: none;
      border-color: var(--primary-color);
      box-shadow: 0 0 0 3px rgba(124, 58, 237, 0.1);
    }

    .checkbox-group {
      display: flex;
      align-items: center;
      gap: 0.5rem;
      width: 100%;
    }

    .checkbox-group input[type="checkbox"] {
      width: auto;
    }

    button {
      background-color: var(--primary-color);
      color: white;
      border: none;
      padding: 0.75rem 1rem;
      font-size: 1rem;
      font-weight: 500;
      border-radius: 0.25rem;
      cursor: pointer;
      transition: background-color 0.3s ease;
    }

    button:hover {
      background-color: var(--primary-hover-color);
    }

    .tooltip {
      position: relative;
      display: inline-block;
      margin-left: 0.5rem;
      cursor: help;
    }

    .tooltip .tooltiptext {
      visibility: hidden;
      width: 200px;
      background-color: #333;
      color: #fff;
      text-align: center;
      border-radius: 6px;
      padding: 5px;
      position: absolute;
      z-index: 1;
      bottom: 125%;
      left: 50%;
      transform: translateX(-50%);
      opacity: 0;
      transition: opacity 0.3s;
    }

    .tooltip:hover .tooltiptext {
      visibility: visible;
      opacity: 1;
    }

    .notification {
      padding: 1rem;
      border-radius: 0.25rem;
      margin-bottom: 1rem;
      text-align: center;
    }

    .notification.success {
      background-color: var(--success-color);
      color: white;
    }

    .notification.error {
      background-color: var(--error-color);
      color: white;
    }

    @media (max-width: 640px) {
      .container {
        margin: 1rem;
        padding: 1rem;
      }
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>Bark Sender</h1>
    <form action="/send" method="post">
      <div>
        <label for="server">
          Bark 后端服务器域名*
        </label>
        <input type="text" id="server" name="server" placeholder="必填项,无需填写到/push端点,默认为官方服务器。" value="https://api.day.app" required>
      </div>
      
      <div>
        <label for="key">
          Key*
        </label>
        <input type="text" id="key" name="key" placeholder="必填项,请输入 Bark App 在添加服务器后生成的密钥。" required>
      </div>
      
      <div>
        <label for="body">
          通知内容*
        </label>
        <textarea id="body" name="body" rows="4" placeholder="必填项,请输入需要推送的通知内容。" required></textarea>
      </div>

      <div>
        <label for="title">
          通知标题
        </label>
        <input type="text" id="title" name="title" placeholder="可设置通知的标题。">
      </div>

      <div>
        <label for="copy">
          指定复制内容
        </label>
        <input type="text" id="copy" name="copy" placeholder="可指定点击复制的内容,留空将默认复制通知内容。">
      </div>

      <div>
        <label for="group">
          分组
        </label>
        <input type="text" id="group" name="group" placeholder="可指定推送消息的分组名称,便于在历史记录中分类查看。">
      </div>

      <div>
        <label for="url">
          跳转 URL
        </label>
        <input type="url" id="url" name="url" placeholder="点击通知,可跳转至填写的URL,支持URL Scheme/Universal Link。">
      </div>

      <div>
        <label for="icon">
          自定义图标
        </label>
        <input type="url" id="icon" name="icon" placeholder="可填入图床链接, iOS15+ 系统版本支持。">
      </div>
      
      <div>
        <label for="sound">
          自定义通知铃声
        </label>
        <input type="text" id="sound" name="sound" list="sound-options" placeholder="可选择预设的通知铃声,亦可前往 Bark App 自行上传。">
        <datalist id="sound-options">
          <option value="alarm">
          <option value="anticipate">
          <option value="bell">
          <option value="birdsong">
          <option value="bloom">
          <option value="calypso">
          <option value="chime">
          <option value="choo">
          <option value="descent">
          <option value="electronic">
          <option value="fanfare">
          <option value="glass">
          <option value="gotosleep">
          <option value="healthnotification">
          <option value="horn">
          <option value="ladder">
          <option value="mailsent">
          <option value="minuet">
          <option value="multiwayinvitation">
          <option value="newmail">
          <option value="newsflash">
          <option value="noir">
          <option value="paymentsuccess">
          <option value="shake">
          <option value="sherwoodforest">
          <option value="silence">
          <option value="spell">
          <option value="suspense">
          <option value="telegraph">
          <option value="tiptoes">
          <option value="typewriters">
          <option value="update">
        </datalist>
      </div>
      
      <div>
        <label for="badge">
          自定义消息数目
        </label>
        <input type="number" id="badge" name="badge" min="1" placeholder="可选,影响单个通知带来的应用角标变动数目,最小值为 1 。">
      </div>
      
      <div>
        <label for="method">
          请求方式
        </label>
        <select id="method" name="method">
          <option value="POST">POST</option>
          <option value="GET">GET(请注意 URL 2k字符长度限制)</option>
        </select>
      </div>

      <div>
        <label for="level">
          通知方式
        </label>
        <select id="level" name="level">
          <option value="active">立即亮屏</option>
          <option value="passive">静默通知</option>
          <option value="timeSensitive">强提醒</option>
        </select>
      </div>

      <div class="checkbox-group">
        <input type="checkbox" id="isArchive" name="isArchive" value="1">
        <label for="isArchive">
          保存到历史记录
        </label>
      </div>

      <div class="checkbox-group">
        <input type="checkbox" id="automaticallyCopy" name="automaticallyCopy" value="1">
        <label for="automaticallyCopy">
          自动复制推送内容
          <span class="tooltip">💡
          <span class="tooltiptext">启用后,通过长按/下拉通知可快速复制通知/指定内容到剪贴板, iOS14.5- 系统版本支持自动复制。</span>
          </span>
        </label>
      </div>

      <button type="submit">确认发送</button>
    </form>
  </div>
  <script>
    document.querySelector('form').addEventListener('submit', function(event) {
      const serverInput = document.getElementById('server');
      const serverUrl = serverInput.value.trim();
      
      if (!/^https?:\\/\\/.+/.test(serverUrl)) {
        event.preventDefault();
        alert('请输入有效的服务器地址,以 http:// 或 https:// 开头');
        serverInput.focus();
      }
    });
  </script>
</body>
</html>
  `;
}

function generateSuccessHTML() {
  return `<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Done - Bark Sender</title>
  <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 16 16%22><text y=%2214%22 font-size=%2214%22>✅</text></svg>">
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
  <style>
    :root {
      --background-color: #F6F9FC;
      --text-color: #1A1F36;
      --success-green: #00C853;
    }
    
    body {
      font-family: 'Inter', sans-serif;
      background-color: var(--background-color);
      color: var(--text-color);
      line-height: 1.5;
      margin: 0;
      padding: 0;
      min-height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    
    .container {
      position: relative;
      z-index: 140;
      width: 100%;
      max-width: 440px;
      margin: auto;
      background-color: white;
      border-radius: 8px;
      padding: 24px 20px;
      text-align: center;
      box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
    }
    
    .success-icon-container {
      width: 100%;
      height: 80px;
      background-color: var(--success-green);
      border-radius: 4px;
      display: flex;
      align-items: center;
      justify-content: center;
      margin-bottom: 20px;
    }
    
    .success-icon {
      width: 48px;
      height: 48px;
    }
    
    .message {
      margin-bottom: 8px;
      font-size: 20px;
      font-weight: 500;
    }
    
    .description {
      margin-bottom: 12px;
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="success-icon-container">
      <svg class="success-icon" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
        <circle cx="24" cy="24" r="24" fill="white"></circle>
        <path d="M32.5 17.5L20.8125 30.5L15.5 25.5" stroke="var(--success-green)" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"></path>
      </svg>
    </div>
    <div>
      <h3 class="message">Done. </h3>
      <span>(Returning in 3 seconds...)</span>
    </div>
  </div>

  <script>
    setTimeout(function() {
      window.location.href = '/';
    }, 3000);
  </script>
</body>
</html>`;
}

以下访问记录仅供参考,建议设置密码确保剪贴板不被非法查看。

ID 设备 访问时间 设备IP IP归属地

暂无访问记录