-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 69a4afb
Showing
23 changed files
with
5,091 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
webpack.config.js | ||
dist | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
env: | ||
es2021: true | ||
node: true | ||
extends: | ||
- standard | ||
- plugin:@typescript-eslint/recommended | ||
- prettier | ||
parser: "@typescript-eslint/parser" | ||
parserOptions: | ||
ecmaVersion: latest | ||
sourceType: module | ||
project: ./tsconfig.json | ||
plugins: | ||
- "@typescript-eslint" | ||
rules: | ||
"@typescript-eslint/no-unused-vars": | ||
- error | ||
- argsIgnorePattern: "^_next$" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
node_modules/ | ||
dist/ | ||
data/* | ||
!data/.gitkeep | ||
config.json | ||
*.env | ||
src/package.json | ||
src/yarn.lock | ||
src/index.html |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"configurations": [ | ||
{ | ||
"type": "node", | ||
"request": "launch", | ||
"name": "Launch", | ||
"runtimeExecutable": "yarn", | ||
"cwd": "${workspaceFolder}", | ||
"runtimeArgs": ["dev"], | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"editor.tabSize": 2 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
FROM zenika/alpine-chrome:with-puppeteer-xvfb as runner | ||
|
||
# hadolint ignore=DL3002 | ||
USER root | ||
|
||
# hadolint ignore=DL3018 | ||
RUN apk upgrade --no-cache --available && \ | ||
apk update && \ | ||
apk add --no-cache \ | ||
x11vnc \ | ||
&& \ | ||
apk add --update --no-cache tzdata && \ | ||
cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \ | ||
echo "Asia/Tokyo" > /etc/timezone && \ | ||
apk del tzdata | ||
|
||
WORKDIR /app | ||
|
||
COPY package.json yarn.lock ./ | ||
|
||
RUN echo network-timeout 600000 > .yarnrc && \ | ||
yarn install --frozen-lockfile && \ | ||
yarn cache clean | ||
|
||
COPY src/ src/ | ||
COPY tsconfig.json .eslintignore .eslintrc.yml . | ||
|
||
COPY entrypoint.sh . | ||
RUN chmod +x entrypoint.sh | ||
|
||
ENV TZ Asia/Tokyo | ||
ENV DISPLAY :99 | ||
ENV CHROMIUM_PATH /usr/bin/chromium-browser | ||
|
||
ENTRYPOINT ["tini", "--"] | ||
CMD ["/app/entrypoint.sh"] |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
version: '3.8' | ||
|
||
services: | ||
app: | ||
build: . | ||
volumes: | ||
- type: bind | ||
source: ./data | ||
target: /data | ||
- type: bind | ||
source: ./config.json | ||
target: /app/config.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#!/bin/sh | ||
|
||
yarn start || true |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
{ | ||
"name": "mfapi", | ||
"version": "0.0.1", | ||
"description": "", | ||
"main": "dist/main.js", | ||
"repository": "git@github.com:sammrai/mfapi.git", | ||
"author": "sammrai", | ||
"license": "MIT", | ||
"private": true, | ||
"scripts": { | ||
"start": "ts-node -r tsconfig-paths/register ./src/main.ts", | ||
"dev": "ts-node-dev --poll --watch src -r tsconfig-paths/register ./src/main.ts", | ||
"package": "run-s clean compile packing", | ||
"packing": "ncc build ./dist/main.js -o output/", | ||
"compile": "tsc -p .", | ||
"clean": "rimraf dist output", | ||
"lint": "run-p -c lint:prettier lint:eslint lint:tsc", | ||
"lint:prettier": "prettier --check src", | ||
"lint:eslint": "eslint . --ext ts,tsx", | ||
"lint:tsc": "tsc", | ||
"fix": "run-s fix:prettier fix:eslint", | ||
"fix:eslint": "eslint . --ext ts,tsx --fix", | ||
"fix:prettier": "prettier --write src", | ||
"watch-openapi": "nodemon --watch ./src/openapi.yaml --exec \"npx @redocly/cli build-docs ./src/openapi.yaml -o ./src/index.html --theme.openapi.disableSearch=true --theme.openapi.expandResponses='200,201'\"", | ||
"serve-docs": "http-server src -p 3001", | ||
"redoc": "npm-run-all --parallel watch-openapi serve-docs" | ||
}, | ||
"devDependencies": { | ||
"@types/node": "20.10.1", | ||
"@types/swagger-ui-express": "^4.1.6", | ||
"@types/yamljs": "^0.2.34", | ||
"@typescript-eslint/eslint-plugin": "6.13.1", | ||
"@typescript-eslint/parser": "6.13.1", | ||
"@vercel/ncc": "0.38.1", | ||
"axios": "1.6.2", | ||
"cheerio": "^1.0.0-rc.12", | ||
"eslint": "8.54.0", | ||
"eslint-config-prettier": "9.0.0", | ||
"eslint-config-standard": "17.1.0", | ||
"eslint-plugin-import": "2.29.0", | ||
"eslint-plugin-n": "16.3.1", | ||
"eslint-plugin-node": "11.1.0", | ||
"eslint-plugin-promise": "6.1.1", | ||
"express": "^4.18.2", | ||
"express-openapi-validator": "^5.1.1", | ||
"prettier": "2.8.8", | ||
"puppeteer-core": "21.5.2", | ||
"swagger-ui-express": "^5.0.0", | ||
"ts-node": "10.9.1", | ||
"ts-node-dev": "2.0.0", | ||
"typescript": "5.3.2", | ||
"yamljs": "^0.3.0", | ||
"yarn-run-all": "3.1.1", | ||
"redoc-express": "^2.1.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import { ApiResponseHandler } from "./api"; | ||
|
||
export enum AccountCategory { | ||
Bank = 2, // 銀行 | ||
Securities = 3, // 証券 | ||
InvestmentTrust = 4, // 投信 | ||
CryptoFXMetals = 5, // 暗号資産・FX・貴金属 | ||
Card = 6, // カード | ||
Pension = 7, // 年金 | ||
EMoneyPrepaid = 8, // 電子マネー・プリペイド | ||
Points = 9, // ポイント | ||
OnlineShopping = 12, // 通販 | ||
Supermarket = 16, // スーパー | ||
OtherAssets = 14, // その他保有資産 | ||
} | ||
|
||
export interface ManualAccount { | ||
name: string; | ||
id: string; | ||
subAccountIdHash: string; | ||
accountString: string; | ||
} | ||
|
||
export default AccountCategory; | ||
|
||
export class Account extends ApiResponseHandler { | ||
public async addManualAccount(category: AccountCategory, name: string) { | ||
const postData = { | ||
"new_manual_account[category_id]": category, | ||
"new_manual_account[name]": name, | ||
}; | ||
|
||
return this.post("/accounts/manual_account", postData); | ||
} | ||
|
||
public async getManualAccounts(): Promise<ManualAccount[]> { | ||
const accounts = await this.get("/accounts", ($) => { | ||
const results: { name: string; id: string }[] = []; | ||
const cssSelector = "section.manual_accounts tr td:first-child a"; | ||
|
||
$(cssSelector).each((_, el) => { | ||
const elem = el; | ||
const name = $(elem).text().trim(); | ||
const href = $(elem).attr("href") || ""; | ||
const id = href.split("/").pop() || ""; | ||
results.push({ name, id }); | ||
}); | ||
|
||
return results; | ||
}); | ||
|
||
// 各アカウントに対して getSubAccountIdHash を非同期的に呼び出す | ||
const enrichedAccounts = await Promise.all( | ||
accounts.map(async (account) => { | ||
const subAccountIdHash = await this.getSubAccountIdHash(account.id); | ||
const accountString = `${account.id}@${subAccountIdHash}`; | ||
return { ...account, subAccountIdHash, accountString }; | ||
}) | ||
); | ||
|
||
return enrichedAccounts; | ||
} | ||
|
||
public async getSubAccountIdHash(accountId: string): Promise<string> { | ||
const url = `/accounts/show_manual/${accountId}`; | ||
|
||
return this.get(url, ($) => { | ||
const value = | ||
$("#user_asset_det_sub_account_id_hash > option") | ||
.first() | ||
.attr("value") || ""; | ||
return value; | ||
}); | ||
} | ||
|
||
public async deleteAccount(accountIdHash: string) { | ||
const postData = { | ||
_method: "delete", | ||
account_id_hash: accountIdHash, | ||
}; | ||
|
||
return this.post("/accounts", postData); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import axios, { AxiosInstance } from "axios"; | ||
import { LoginSession } from "../authentication"; | ||
import cheerio, { CheerioAPI } from "cheerio"; | ||
|
||
export abstract class ApiResponseHandler { | ||
private axiosInstance: AxiosInstance; | ||
|
||
constructor(session: LoginSession) { | ||
this.axiosInstance = axios.create({ | ||
baseURL: "https://moneyforward.com", | ||
headers: { | ||
cookie: this.formatCookies(session.cookie), | ||
origin: "https://moneyforward.com", | ||
referer: "https://moneyforward.com/", | ||
"x-csrf-token": session["csrf-token"], | ||
"x-requested-with": "XMLHttpRequest", | ||
"Content-Type": "application/x-www-form-urlencoded", | ||
}, | ||
transformRequest: [ | ||
function (data) { | ||
if (data) { | ||
return Object.entries(data) | ||
.map( | ||
([key, value]) => | ||
`${encodeURIComponent(key)}=${encodeURIComponent( | ||
String(value) | ||
)}` | ||
) | ||
.join("&"); | ||
} | ||
return data; | ||
}, | ||
], | ||
}); | ||
} | ||
|
||
private formatCookies( | ||
cookies: Array<{ name: string; value: string }> | ||
): string { | ||
return cookies.map((cookie) => `${cookie.name}=${cookie.value}`).join("; "); | ||
} | ||
|
||
protected async post<T, U = T>(url: string, data?: T): Promise<U> { | ||
try { | ||
const response = await this.axiosInstance.post<U>(url, data); | ||
// console.log("SUCCESS:", response.data); | ||
console.log("Status Code: ", response.status); | ||
// console.log("Response Headers: ", response.headers); | ||
return response.data; | ||
} catch (error) { | ||
console.error("ERROR:", error); | ||
throw error; | ||
} | ||
} | ||
|
||
protected async get<T>( | ||
url: string, | ||
decorator: (cheerio: CheerioAPI) => T | ||
): Promise<T> { | ||
const response = await this.axiosInstance.get(url); | ||
console.log("Status Code: ", response.status); | ||
// console.log("Response Headers: ", response.headers); | ||
const $ = cheerio.load(response.data); | ||
return decorator($); | ||
} | ||
} |
Oops, something went wrong.