n8n-nodes-amis-v1 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -132,8 +132,9 @@ class MisaAmis {
|
|
|
132
132
|
// 1. Load Session
|
|
133
133
|
const credentials = await this.getCredentials('misaAmisUser');
|
|
134
134
|
const userIdentity = credentials.userIdentity;
|
|
135
|
+
const safeIdentity = userIdentity.replace(/[^a-z0-9]/gi, '_').toLowerCase();
|
|
135
136
|
const n8nDir = process.env.N8N_USER_FOLDER || path.join(os.homedir(), '.n8n');
|
|
136
|
-
const sessionFilePath = path.join(n8nDir, 'misa_sessions', `${
|
|
137
|
+
const sessionFilePath = path.join(n8nDir, 'misa_sessions', `${safeIdentity}.json`);
|
|
137
138
|
if (!fs.existsSync(sessionFilePath)) {
|
|
138
139
|
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Session file not found for user: ${userIdentity}. Please run Login Node first.`);
|
|
139
140
|
}
|
|
@@ -99,19 +99,7 @@ class MisaAmisLogin {
|
|
|
99
99
|
},
|
|
100
100
|
},
|
|
101
101
|
},
|
|
102
|
-
|
|
103
|
-
displayName: 'Request ID',
|
|
104
|
-
name: 'requestId',
|
|
105
|
-
type: 'string',
|
|
106
|
-
default: '',
|
|
107
|
-
required: true,
|
|
108
|
-
displayOptions: {
|
|
109
|
-
show: {
|
|
110
|
-
operation: ['checkLogin'],
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
description: 'The CDRequestId returned from "Generate QR" step',
|
|
114
|
-
},
|
|
102
|
+
// Removed requestId and cookieJar inputs because we use file-based state
|
|
115
103
|
],
|
|
116
104
|
};
|
|
117
105
|
}
|
|
@@ -120,11 +108,20 @@ class MisaAmisLogin {
|
|
|
120
108
|
const returnData = [];
|
|
121
109
|
const operation = this.getNodeParameter('operation', 0);
|
|
122
110
|
const userIdentity = this.getNodeParameter('userIdentity', 0);
|
|
111
|
+
const safeIdentity = userIdentity.replace(/[^a-z0-9]/gi, '_').toLowerCase();
|
|
123
112
|
const n8nDir = process.env.N8N_USER_FOLDER || path.join(os.homedir(), '.n8n');
|
|
124
113
|
const storagePath = path.join(n8nDir, 'misa_sessions');
|
|
125
|
-
|
|
126
|
-
fs.
|
|
114
|
+
try {
|
|
115
|
+
if (!fs.existsSync(storagePath)) {
|
|
116
|
+
fs.mkdirSync(storagePath, { recursive: true });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Failed to create storage directory '${storagePath}': ${error.message}. Please check permissions.`);
|
|
127
121
|
}
|
|
122
|
+
// File paths
|
|
123
|
+
const sessionFilePath = path.join(storagePath, `${safeIdentity}.json`);
|
|
124
|
+
const pendingFilePath = path.join(storagePath, `${safeIdentity}.pending.json`);
|
|
128
125
|
const clientId = '6bcbc4d1-5426-42f7-bc61-69cac2e229f4';
|
|
129
126
|
const headers = {
|
|
130
127
|
'Content-Type': 'application/json',
|
|
@@ -155,11 +152,19 @@ class MisaAmisLogin {
|
|
|
155
152
|
const cdRequestId = genQrRes.data.CDRequestId;
|
|
156
153
|
const qrContent = `https://amisapp.misa.vn/shared?app=qrlogin&qrid=${cdRequestId}&domain=amisapp.misa.vn`;
|
|
157
154
|
const qrBuffer = await qrcode_1.default.toBuffer(qrContent);
|
|
155
|
+
// SAVE PENDING STATE
|
|
156
|
+
const serializedJar = await jar.serialize();
|
|
157
|
+
const pendingState = {
|
|
158
|
+
requestId: cdRequestId,
|
|
159
|
+
cookieJar: serializedJar,
|
|
160
|
+
timestamp: Date.now()
|
|
161
|
+
};
|
|
162
|
+
fs.writeFileSync(pendingFilePath, JSON.stringify(pendingState, null, 2));
|
|
158
163
|
returnData.push({
|
|
159
164
|
json: {
|
|
160
|
-
message: "QR Generated. Scan
|
|
165
|
+
message: "QR Generated. Please Scan. Pending session saved.",
|
|
166
|
+
userIdentity: userIdentity,
|
|
161
167
|
requestId: cdRequestId,
|
|
162
|
-
clientId: clientId,
|
|
163
168
|
qrContent: qrContent
|
|
164
169
|
},
|
|
165
170
|
binary: {
|
|
@@ -173,16 +178,31 @@ class MisaAmisLogin {
|
|
|
173
178
|
}
|
|
174
179
|
else if (operation === 'checkLogin') {
|
|
175
180
|
// --- Operation: Check Login ---
|
|
176
|
-
|
|
177
|
-
|
|
181
|
+
// READ PENDING STATE
|
|
182
|
+
if (!fs.existsSync(pendingFilePath)) {
|
|
183
|
+
const allFiles = fs.readdirSync(storagePath);
|
|
184
|
+
const pendingFiles = allFiles.filter(f => f.endsWith('.pending.json'));
|
|
185
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `No pending login found for user '${userIdentity}'. Path: ${pendingFilePath}. Available pending sessions: ${pendingFiles.join(', ')}`);
|
|
186
|
+
}
|
|
187
|
+
const pendingState = JSON.parse(fs.readFileSync(pendingFilePath, 'utf8'));
|
|
188
|
+
const cdRequestId = pendingState.requestId;
|
|
189
|
+
// Restore Cookies
|
|
190
|
+
if (pendingState.cookieJar) {
|
|
191
|
+
const deserialized = await tough_cookie_1.CookieJar.deserialize(pendingState.cookieJar);
|
|
192
|
+
await jar.removeAllCookies();
|
|
193
|
+
for (const cookie of await deserialized.getCookies('https://id.misa.vn')) {
|
|
194
|
+
await jar.setCookie(cookie, 'https://id.misa.vn');
|
|
195
|
+
}
|
|
196
|
+
}
|
|
178
197
|
let pollingSuccess = false;
|
|
179
198
|
let attempts = 0;
|
|
180
|
-
const maxAttempts = 60; // 2 minutes
|
|
199
|
+
const maxAttempts = 60; // 2 minutes
|
|
181
200
|
while (!pollingSuccess && attempts < maxAttempts) {
|
|
182
201
|
attempts++;
|
|
183
202
|
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
184
203
|
try {
|
|
185
204
|
const pollUrl = `https://id.misa.vn/api/login-cross-device/v2/polling?cdRequestId=${cdRequestId}&clientId=${clientId}&deviceId=${clientId}`;
|
|
205
|
+
console.log(`[MISA Debug] Polling Attempt ${attempts}: ${pollUrl}`);
|
|
186
206
|
const pollRes = await client.get(pollUrl, { headers });
|
|
187
207
|
if (JSON.stringify(pollRes.data).includes("Success") || JSON.stringify(pollRes.data).includes("v1/auth/token")) {
|
|
188
208
|
pollingSuccess = true;
|
|
@@ -190,15 +210,19 @@ class MisaAmisLogin {
|
|
|
190
210
|
}
|
|
191
211
|
catch (error) {
|
|
192
212
|
if (error.response && error.response.status >= 400 && error.response.status < 500) {
|
|
193
|
-
|
|
194
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Polling Error ${error.response.status}: ${JSON.stringify(error.response.data)}. Please Generate QR again.`);
|
|
213
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `Polling Error: ${JSON.stringify(error.response.data)}. Please Generate QR again.`);
|
|
195
214
|
}
|
|
196
|
-
// Ignore server errors or network glitches (retry)
|
|
197
215
|
}
|
|
198
216
|
}
|
|
199
217
|
if (pollingSuccess) {
|
|
218
|
+
// Save FINAL Session
|
|
200
219
|
const serializedJar = await jar.serialize();
|
|
201
220
|
fs.writeFileSync(sessionFilePath, JSON.stringify(serializedJar, null, 2));
|
|
221
|
+
// Cleanup Pending
|
|
222
|
+
try {
|
|
223
|
+
fs.unlinkSync(pendingFilePath);
|
|
224
|
+
}
|
|
225
|
+
catch (e) { }
|
|
202
226
|
returnData.push({
|
|
203
227
|
json: {
|
|
204
228
|
message: "Login Successful",
|
|
@@ -208,7 +232,7 @@ class MisaAmisLogin {
|
|
|
208
232
|
});
|
|
209
233
|
}
|
|
210
234
|
else {
|
|
211
|
-
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Login timeout
|
|
235
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Login timeout. Please scan QR Code again.');
|
|
212
236
|
}
|
|
213
237
|
}
|
|
214
238
|
}
|