-
-
Save fahrradflucht/0a9776132869dbc9d369c90ef29f20fc to your computer and use it in GitHub Desktop.
import * as crypto from "crypto"; | |
import fetch, { Headers } from "node-fetch"; | |
import { promisify } from "util"; | |
const pbkdf2 = promisify(crypto.pbkdf2); | |
const endpoint = "https://sync.standardnotes.org"; | |
const email = process.env.SN_EMAIL || ""; | |
const uip = process.env.SN_PASSWORD || ""; | |
interface AuthParamsResponse { | |
identifier: string; | |
pw_salt: string; | |
pw_cost: number; | |
pw_nonce: string; | |
version: string; | |
pw_func: string; | |
pw_alg: string; | |
pw_key_size: number; | |
} | |
async function login(): Promise<void> { | |
const { | |
pw_cost, | |
pw_nonce, | |
version | |
}: AuthParamsResponse = await fetch( | |
`${endpoint}/auth/params?email=${email}` | |
).then(res => res.json()); | |
const salt = crypto | |
.createHash("sha256") | |
.update([email, "SF", version, pw_cost, pw_nonce].join(":"), "utf8") | |
.digest() | |
.toString("hex"); | |
const key = (await pbkdf2(uip, salt, pw_cost, 768, "sha512")).toString("hex"); | |
const splitLength = key.length / 3; | |
const pw = key.slice(0, splitLength); | |
// const mk = key.slice(splitLength, splitLength * 2); | |
// const ak = key.slice(splitLength * 2, splitLength * 3); | |
const token = await fetch(`${endpoint}/auth/sign_in`, { | |
method: "POST", | |
headers: new Headers({ | |
"Content-Type": "application/json" | |
}), | |
body: JSON.stringify({ | |
password: pw, | |
email: "[email protected]" | |
}) | |
}).then(res => res.json()); | |
console.log(token); | |
} | |
login().catch(console.error); |
pw_func, pw_alg, pw_key_size are all deprecated and no longer used. You might get these values returned if your account was created a long time ago, but new accounts do not use these values. Instead, the algorithm and keysize are attached to the version
that is returned for the account. 002 and 003 both use the same hardcoded algorithms: pbkdf2 with sha512 and a key size of 768.
I recommend subclassing the SFAbstractCrypto class and overriding the methods where you need to provide custom functionality.
Also, Node's pbkdf2 looks like it takes the number of bytes as the keylen input param, not bits. So it should probably be 768/8.
@mobitar Ah this is where the body is buried. bits and bytes! Should have figured that out myself once I found out that it works with 96. Thanks for your support. I see if sub-classing SFAbstractCrypto is feasable our if I build the rest out myself as well 😄
Sounds good. PS I don't get notified of comments inside gists or commits for whatever reason. So be sure to update the original issue if you come across any other issues.
I am super confused. I compared what I send to the payload standard notes sends on the web and found out that the
password
send is64
long. So if I change this code to compute the PBKDF2 with SHA512 to only produce 96bit output which results in a 192 char long hex string this code works.