mirror of
https://github.com/wkulhanek/bonob.git
synced 2025-12-21 17:33:29 +01:00
Use sha256 for access tokens
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
import dayjs, { Dayjs } from "dayjs";
|
import dayjs, { Dayjs } from "dayjs";
|
||||||
import { v4 as uuid } from "uuid";
|
import { v4 as uuid } from "uuid";
|
||||||
|
import crypto from "crypto";
|
||||||
|
|
||||||
import { Encryption } from "./encryption";
|
import { Encryption } from "./encryption";
|
||||||
import logger from "./logger";
|
import logger from "./logger";
|
||||||
|
|
||||||
@@ -94,3 +96,25 @@ export class AccessTokenPerAuthToken implements AccessTokens {
|
|||||||
|
|
||||||
authTokenFor = (value: string): string | undefined => this.accessTokenToAuthToken.get(value);
|
authTokenFor = (value: string): string | undefined => this.accessTokenToAuthToken.get(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const sha256 = (salt: string) => (authToken: string) => crypto
|
||||||
|
.createHash("sha256")
|
||||||
|
.update(`${authToken}${salt}`)
|
||||||
|
.digest("hex")
|
||||||
|
|
||||||
|
export class InMemoryAccessTokens implements AccessTokens {
|
||||||
|
tokens = new Map<string, string>();
|
||||||
|
minter;
|
||||||
|
|
||||||
|
constructor(minter: (authToken: string) => string) {
|
||||||
|
this.minter = minter
|
||||||
|
}
|
||||||
|
|
||||||
|
mint = (authToken: string): string => {
|
||||||
|
const accessToken = this.minter(authToken);
|
||||||
|
this.tokens.set(accessToken, authToken);
|
||||||
|
return accessToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
authTokenFor = (value: string): string | undefined => this.tokens.get(value);
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import server from "./server";
|
|||||||
import logger from "./logger";
|
import logger from "./logger";
|
||||||
import { Navidrome } from "./navidrome";
|
import { Navidrome } from "./navidrome";
|
||||||
import encryption from "./encryption";
|
import encryption from "./encryption";
|
||||||
|
import { InMemoryAccessTokens, sha256 } from "./access_tokens";
|
||||||
|
import { InMemoryLinkCodes } from "./link_codes";
|
||||||
|
|
||||||
const PORT = +(process.env["BONOB_PORT"] || 4534);
|
const PORT = +(process.env["BONOB_PORT"] || 4534);
|
||||||
const WEB_ADDRESS =
|
const WEB_ADDRESS =
|
||||||
@@ -18,6 +20,7 @@ const bonob = bonobService(
|
|||||||
WEB_ADDRESS,
|
WEB_ADDRESS,
|
||||||
"AppLink"
|
"AppLink"
|
||||||
);
|
);
|
||||||
|
const secret = process.env["BONOB_SECRET"] || "bonob";
|
||||||
|
|
||||||
const sonosSystem = sonos(SONOS_DEVICE_DISCOVERY, SONOS_SEED_HOST);
|
const sonosSystem = sonos(SONOS_DEVICE_DISCOVERY, SONOS_SEED_HOST);
|
||||||
if(process.env["BONOB_SONOS_AUTO_REGISTER"] == "true") {
|
if(process.env["BONOB_SONOS_AUTO_REGISTER"] == "true") {
|
||||||
@@ -34,8 +37,10 @@ const app = server(
|
|||||||
WEB_ADDRESS,
|
WEB_ADDRESS,
|
||||||
new Navidrome(
|
new Navidrome(
|
||||||
process.env["BONOB_NAVIDROME_URL"] || "http://localhost:4533",
|
process.env["BONOB_NAVIDROME_URL"] || "http://localhost:4533",
|
||||||
encryption(process.env["BONOB_SECRET"] || "bonob")
|
encryption(secret)
|
||||||
)
|
),
|
||||||
|
new InMemoryLinkCodes(),
|
||||||
|
new InMemoryAccessTokens(sha256(secret))
|
||||||
);
|
);
|
||||||
|
|
||||||
app.listen(PORT, () => {
|
app.listen(PORT, () => {
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import {
|
|||||||
AccessTokenPerAuthToken,
|
AccessTokenPerAuthToken,
|
||||||
EncryptedAccessTokens,
|
EncryptedAccessTokens,
|
||||||
ExpiringAccessTokens,
|
ExpiringAccessTokens,
|
||||||
|
InMemoryAccessTokens,
|
||||||
|
sha256
|
||||||
} from "../src/access_tokens";
|
} from "../src/access_tokens";
|
||||||
import { Encryption } from "../src/encryption";
|
import { Encryption } from "../src/encryption";
|
||||||
|
|
||||||
@@ -207,5 +209,65 @@ describe("AccessTokenPerAuthToken", () => {
|
|||||||
expect(accessTokens.authTokenFor(uuid())).toBeUndefined();
|
expect(accessTokens.authTokenFor(uuid())).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('sha256 minter', () => {
|
||||||
|
it('should return the same value for the same salt and authToken', () => {
|
||||||
|
const authToken = uuid();
|
||||||
|
const token1 = sha256("salty")(authToken);
|
||||||
|
const token2 = sha256("salty")(authToken);
|
||||||
|
|
||||||
|
expect(token1).not.toEqual(authToken);
|
||||||
|
expect(token1).toEqual(token2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should returrn different values for the same salt but different authTokens', () => {
|
||||||
|
const authToken1 = uuid();
|
||||||
|
const authToken2 = uuid();
|
||||||
|
|
||||||
|
const token1 = sha256("salty")(authToken1);
|
||||||
|
const token2= sha256("salty")(authToken2);
|
||||||
|
|
||||||
|
expect(token1).not.toEqual(token2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return different values for the same authToken but different salts', () => {
|
||||||
|
const authToken = uuid();
|
||||||
|
|
||||||
|
const token1 = sha256("salt1")(authToken);
|
||||||
|
const token2= sha256("salt2")(authToken);
|
||||||
|
|
||||||
|
expect(token1).not.toEqual(token2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("InMemoryAccessTokens", () => {
|
||||||
|
const reverseAuthToken = (authToken: string) => authToken.split("").reverse().join("");
|
||||||
|
|
||||||
|
const accessTokens = new InMemoryAccessTokens(reverseAuthToken);
|
||||||
|
|
||||||
|
it("should return the same access token for the same auth token", () => {
|
||||||
|
const authToken = "token1";
|
||||||
|
|
||||||
|
const accessToken1 = accessTokens.mint(authToken);
|
||||||
|
const accessToken2 = accessTokens.mint(authToken);
|
||||||
|
|
||||||
|
expect(accessToken1).not.toEqual(authToken);
|
||||||
|
expect(accessToken1).toEqual(accessToken2);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when there is an auth token for the access token", () => {
|
||||||
|
it("should be able to retrieve it", () => {
|
||||||
|
const authToken = uuid();
|
||||||
|
const accessToken = accessTokens.mint(authToken);
|
||||||
|
|
||||||
|
expect(accessTokens.authTokenFor(accessToken)).toEqual(authToken);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("when there is no auth token for the access token", () => {
|
||||||
|
it("should return undefined", () => {
|
||||||
|
expect(accessTokens.authTokenFor(uuid())).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user