feat new s3 public url option
This commit is contained in:
8
bun.lock
8
bun.lock
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"configVersion": 0,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "dsas-cca-backend-bun",
|
||||
@@ -16,9 +17,10 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
"typescript-language-server": "^5.1.3",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5",
|
||||
"typescript": "^5.9.3",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -247,7 +249,9 @@
|
||||
|
||||
"type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
|
||||
|
||||
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
|
||||
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||
|
||||
"typescript-language-server": ["typescript-language-server@5.1.3", "", { "bin": { "typescript-language-server": "lib/cli.mjs" } }, "sha512-r+pAcYtWdN8tKlYZPwiiHNA2QPjXnI02NrW5Sf2cVM3TRtuQ3V9EKKwOxqwaQ0krsaEXk/CbN90I5erBuf84Vg=="],
|
||||
|
||||
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ PORT=3000
|
||||
FIXED_STAFF_ACTIVITY_ID=7095
|
||||
ALLOWED_ORIGINS=*
|
||||
S3_ENDPOINT=
|
||||
S3_PUBLIC_URL=
|
||||
S3_BUCKET_NAME=
|
||||
S3_ACCESS_KEY_ID=
|
||||
S3_SECRET_ACCESS_KEY=
|
||||
|
||||
112
extract-login-form.js
Normal file
112
extract-login-form.js
Normal file
@@ -0,0 +1,112 @@
|
||||
import { chromium } from 'playwright';
|
||||
|
||||
async function extractLoginForm() {
|
||||
const browser = await chromium.launch({ headless: true });
|
||||
const page = await browser.newPage();
|
||||
|
||||
console.log('Navigating to login page...\n');
|
||||
await page.goto('https://engage.nkcswx.cn/Login.aspx');
|
||||
await page.waitForLoadState('networkidle');
|
||||
|
||||
// Extract all form fields
|
||||
const formFields = await page.evaluate(() => {
|
||||
const form = document.querySelector('form');
|
||||
if (!form) return { error: 'No form found' };
|
||||
|
||||
const fields = [];
|
||||
|
||||
// Get all inputs from the form
|
||||
const inputs = form.querySelectorAll('input, select, textarea');
|
||||
inputs.forEach((input, index) => {
|
||||
fields.push({
|
||||
index,
|
||||
type: input.tagName,
|
||||
name: input.name || '(no name)',
|
||||
id: input.id || '(no id)',
|
||||
inputType: input.type || 'N/A',
|
||||
value: input.type === 'password' ? '[HIDDEN]' : (input.value || '(empty)'),
|
||||
placeholder: input.placeholder || '(none)',
|
||||
required: input.required ? 'yes' : 'no',
|
||||
autocomplete: input.autocomplete || '(none)'
|
||||
});
|
||||
});
|
||||
|
||||
// Get form attributes
|
||||
const formAttrs = {
|
||||
action: form.action,
|
||||
method: form.method,
|
||||
enctype: form.enctype,
|
||||
target: form.target
|
||||
};
|
||||
|
||||
return { formAttrs, fields };
|
||||
});
|
||||
|
||||
if (formFields.error) {
|
||||
console.error(formFields.error);
|
||||
await browser.close();
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('='.repeat(70));
|
||||
console.log('FORM ATTRIBUTES');
|
||||
console.log('='.repeat(70));
|
||||
console.log(`Action: ${formFields.formAttrs.action}`);
|
||||
console.log(`Method: ${formFields.formAttrs.method}`);
|
||||
console.log(`Enctype: ${formFields.formAttrs.enctype}`);
|
||||
console.log(`Target: ${formFields.formAttrs.target || '(default)'}`);
|
||||
console.log('');
|
||||
|
||||
console.log('='.repeat(70));
|
||||
console.log('ALL FORM FIELDS');
|
||||
console.log('='.repeat(70));
|
||||
console.log('');
|
||||
|
||||
// Group fields by type
|
||||
const hiddenFields = formFields.fields.filter(f => f.inputType === 'hidden');
|
||||
const visibleFields = formFields.fields.filter(f => f.inputType !== 'hidden');
|
||||
|
||||
// Show hidden fields first (critical for ASP.NET)
|
||||
if (hiddenFields.length > 0) {
|
||||
console.log('📦 HIDDEN FIELDS (critical for form submission):');
|
||||
console.log('-'.repeat(70));
|
||||
hiddenFields.forEach(field => {
|
||||
console.log(` Name: ${field.name}`);
|
||||
console.log(` Value: ${field.value.substring(0, 80)}${field.value.length > 80 ? '...' : ''}`);
|
||||
console.log(` Length: ${field.value.length} chars`);
|
||||
console.log('');
|
||||
});
|
||||
}
|
||||
|
||||
// Show visible fields
|
||||
if (visibleFields.length > 0) {
|
||||
console.log('\n📝 VISIBLE FIELDS:');
|
||||
console.log('-'.repeat(70));
|
||||
visibleFields.forEach(field => {
|
||||
console.log(` Name: ${field.name}`);
|
||||
console.log(` Type: ${field.inputType}`);
|
||||
console.log(` ID: ${field.id}`);
|
||||
console.log(` Placeholder: ${field.placeholder}`);
|
||||
console.log(` Required: ${field.required}`);
|
||||
console.log(` Autocomplete: ${field.autocomplete}`);
|
||||
console.log('');
|
||||
});
|
||||
}
|
||||
|
||||
// Summary of field names
|
||||
console.log('='.repeat(70));
|
||||
console.log('FIELD NAME SUMMARY (for authentication payload):');
|
||||
console.log('='.repeat(70));
|
||||
formFields.fields.forEach(field => {
|
||||
const marker = field.inputType === 'hidden' ? '[HIDDEN]' : '[VISIBLE]';
|
||||
console.log(` ${marker} ${field.name}`);
|
||||
});
|
||||
|
||||
// Take a screenshot for visual reference
|
||||
await page.screenshot({ path: 'login-page-screenshot.png', fullPage: true });
|
||||
console.log('\n📸 Screenshot saved to: login-page-screenshot.png');
|
||||
|
||||
await browser.close();
|
||||
}
|
||||
|
||||
extractLoginForm().catch(console.error);
|
||||
@@ -6,10 +6,11 @@
|
||||
"dev": "bun run --watch index.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest"
|
||||
"@types/bun": "latest",
|
||||
"typescript-language-server": "^5.1.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5"
|
||||
"typescript": "^5.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.9.0",
|
||||
|
||||
@@ -15,6 +15,7 @@ const S3_REGION = process.env.S3_REGION;
|
||||
const S3_ACCESS_KEY_ID = process.env.S3_ACCESS_KEY_ID;
|
||||
const S3_SECRET_ACCESS_KEY = process.env.S3_SECRET_ACCESS_KEY;
|
||||
const BUCKET_NAME = process.env.S3_BUCKET_NAME;
|
||||
const S3_PUBLIC_URL = process.env.S3_PUBLIC_URL;
|
||||
const PUBLIC_URL_FILE_PREFIX = (process.env.S3_PUBLIC_URL_PREFIX || 'files').replace(/\/$/, '');
|
||||
|
||||
// Initialize S3 client
|
||||
@@ -195,6 +196,7 @@ export async function deleteS3Objects(objectKeysArray: string[]): Promise<boolea
|
||||
|
||||
/**
|
||||
* Constructs the public S3 URL for an object key.
|
||||
* Uses S3_PUBLIC_URL if set (reverse proxy scenario), otherwise uses S3_ENDPOINT.
|
||||
* @param objectKey - The key of the object in S3
|
||||
* @returns The full public URL
|
||||
*/
|
||||
@@ -202,8 +204,8 @@ export function constructS3Url(objectKey: string): string {
|
||||
if (!S3_ENDPOINT || !BUCKET_NAME) {
|
||||
return '';
|
||||
}
|
||||
// Ensure S3_ENDPOINT does not end with a slash
|
||||
const s3Base = S3_ENDPOINT.replace(/\/$/, '');
|
||||
// Use S3_PUBLIC_URL if set (reverse proxy), otherwise use S3_ENDPOINT
|
||||
const s3Base = (S3_PUBLIC_URL || S3_ENDPOINT).replace(/\/$/, '');
|
||||
// Ensure BUCKET_NAME does not start or end with a slash
|
||||
const bucket = BUCKET_NAME.replace(/^\//, '').replace(/\/$/, '');
|
||||
// Ensure objectKey does not start with a slash
|
||||
|
||||
Reference in New Issue
Block a user