Skip to content

Commit b65b24d

Browse files
authored
[basisbank-ge] add initial support (#941)
1 parent 7ba6076 commit b65b24d

File tree

10 files changed

+1874
-4
lines changed

10 files changed

+1874
-4
lines changed

.gitignore

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,20 @@ Thumbs.db
5353
/yarn-error.log
5454
/.yarnrc
5555
/.yarn/
56+
57+
# repository docs/plans
58+
AGENT.md
59+
AGENTS.md
60+
*PLAN*.md
61+
plans/archive/
62+
**/plans/archive/
63+
64+
# local AI/context artifacts
65+
*llm.txt
66+
review/
67+
68+
# local capture/debug artifacts
69+
.local/
70+
.tmp-*/
71+
.tmp-*
72+
BASISBANK_LOCAL_TEST_STEPS.md

scripts/wrapper.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,21 @@ if (pluginIndex !== -1) {
99
args = args.slice(0, pluginIndex).concat(`PLUGIN=${pluginValue}`)
1010
}
1111

12-
const result = spawnSync(command, args, {
12+
const spawnOptions = {
1313
env: { ...process.env, NODE_OPTIONS: `--max-old-space-size=${Math.floor(os.totalmem() / (1024 * 1024))}` },
14-
stdio: 'inherit'
15-
})
14+
stdio: 'inherit',
15+
shell: process.platform === 'win32'
16+
}
17+
18+
const result = spawnSync(command, args, spawnOptions)
19+
20+
if (result.error) {
21+
console.error(`Failed to start command "${command}":`, result.error.message)
22+
process.exit(1)
23+
}
24+
25+
if (typeof result.status !== 'number') {
26+
process.exit(1)
27+
}
28+
1629
process.exit(result.status)

src/handleMessageFromWindow.js

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,61 @@
11
import { ZPAPI } from './ZPAPI'
22

3+
function toSerializableError (error) {
4+
if (error == null) {
5+
return {
6+
name: 'Error',
7+
message: 'Unknown error',
8+
fatal: false,
9+
allowRetry: false,
10+
allow_retry: false
11+
}
12+
}
13+
14+
const seen = new WeakSet()
15+
const sanitize = (value) => {
16+
if (value == null || typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
17+
return value
18+
}
19+
if (typeof value === 'function' || typeof value === 'symbol' || typeof value === 'bigint') {
20+
return undefined
21+
}
22+
if (Array.isArray(value)) {
23+
return value.map(sanitize)
24+
}
25+
if (typeof value === 'object') {
26+
if (seen.has(value)) {
27+
return '[Circular]'
28+
}
29+
seen.add(value)
30+
const out = {}
31+
for (const [key, nested] of Object.entries(value)) {
32+
const clean = sanitize(nested)
33+
if (clean !== undefined) {
34+
out[key] = clean
35+
}
36+
}
37+
return out
38+
}
39+
return undefined
40+
}
41+
42+
const payload = sanitize(error)
43+
const result = typeof payload === 'object' && payload != null ? payload : { message: String(error) }
44+
if (typeof error.name === 'string' && result.name == null) {
45+
result.name = error.name
46+
}
47+
if (typeof error.message === 'string' && result.message == null) {
48+
result.message = error.message
49+
}
50+
if (typeof error.stack === 'string' && result.stack == null) {
51+
result.stack = error.stack
52+
}
53+
result.fatal = Boolean(result.fatal)
54+
result.allowRetry = Boolean(result.allowRetry || result.allow_retry)
55+
result.allow_retry = result.allowRetry
56+
return result
57+
}
58+
359
const messageHandlers = {
460
':commands/execute-sync': async ({ payload: { manifest, preferences, data }, reply }) => {
561
reply({ type: ':events/scrape-started' })
@@ -16,7 +72,7 @@ const messageHandlers = {
1672
} catch (error) {
1773
reply({
1874
type: ':events/scrape-error',
19-
payload: error
75+
payload: toSerializableError(error)
2076
})
2177
}
2278
},

src/plugins/basisbank/README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# BasisBank Plugin (User Flow)
2+
3+
## What This Plugin Uses
4+
- BasisBank user internet-banking flow at `https://www.bankonline.ge`
5+
- Session cookies persisted through ZenMoney cookie storage
6+
- Card/account endpoints used by the web cabinet:
7+
- `GET/POST /Login.aspx`
8+
- `GET/POST /Balance.aspx`
9+
- `POST /Handlers/BToolkit.ashx?Action=GetSessionId&Type=Login|DeviceBinding`
10+
- `POST /Handlers/SendSms.ashx?Module=BankOnlineTransfer`
11+
- `POST /Handlers/CardModule.ashx?funq=checksession|getcardlist|getlasttransactionlist`
12+
13+
## Preferences
14+
- `login`: internet-banking login
15+
- `password`: internet-banking password
16+
- `requestSmsCode` (default `true`): trigger bank SMS endpoint before OTP prompt
17+
- `trustDevice` (default `true`): attempt trusted-device confirmation when bank requests it
18+
- `startDate`: initial sync date
19+
20+
## Authentication Behavior
21+
- Plugin restores saved cookies first.
22+
- If session is dead, plugin performs login flow and OTP confirmation.
23+
- If trusted-device popup flow is presented, plugin can complete it using OTP and then persist updated cookies.
24+
25+
## Known Limits
26+
- Flow depends on current bank web behavior and endpoint contracts.
27+
- If bank changes markup/hidden fields, login flow may need parser updates.
28+
- If OTP is required and code is not entered in time, synchronization fails with OTP error.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<provider>
3+
<id>basisbank</id>
4+
<version>1.0</version>
5+
<build>1</build>
6+
<company>0</company>
7+
<modular>true</modular>
8+
<codeRequired>false</codeRequired>
9+
<files>
10+
<js>index.js</js>
11+
<preferences>preferences.xml</preferences>
12+
</files>
13+
<description>
14+
BasisBank Internet Banking synchronization plugin (user flow).
15+
Uses login/password with OTP and trusted-device session persistence.
16+
</description>
17+
</provider>

0 commit comments

Comments
 (0)