// import Cookies from 'js-cookie'; import { Err, None, Ok, Option, Result, Some } from "@sniptt/monads"; import IsomorphicCookie from "isomorphic-cookie"; import jwt_decode from "jwt-decode"; import { LoginResponse, MyUserInfo } from "lemmy-js-client"; import { BehaviorSubject, Subject } from "rxjs"; import { isHttps } from "../env"; import { i18n } from "../i18next"; import { isBrowser, toast } from "../utils"; interface Claims { sub: number; iss: string; iat: number; } interface JwtInfo { claims: Claims; jwt: string; } export class UserService { private static _instance: UserService; public myUserInfo: Option = None; public jwtInfo: Option = None; public jwtSub: Subject> = new Subject>(); public unreadInboxCountSub: BehaviorSubject = new BehaviorSubject(0); public unreadReportCountSub: BehaviorSubject = new BehaviorSubject(0); public unreadApplicationCountSub: BehaviorSubject = new BehaviorSubject(0); private constructor() { this.setJwtInfo(); } public login(res: LoginResponse) { let expires = new Date(); expires.setDate(expires.getDate() + 365); IsomorphicCookie.save("jwt", res.jwt, { expires, secure: isHttps }); console.log("jwt cookie set"); this.setJwtInfo(); } public logout() { this.jwtInfo = None; this.myUserInfo = None; this.jwtSub.next(this.jwtInfo); IsomorphicCookie.remove("jwt"); // TODO is sometimes unreliable for some reason document.cookie = "jwt=; Max-Age=0; path=/; domain=" + location.host; location.reload(); // TODO may not be necessary anymore console.log("Logged out."); } public auth(throwErr = true): Result { // Can't use match to convert to result for some reason let jwt = this.jwtInfo.map(j => j.jwt); if (jwt.isSome()) { return Ok(jwt.unwrap()); } else { let msg = "No JWT cookie found"; if (throwErr && isBrowser()) { console.log(msg); toast(i18n.t("not_logged_in"), "danger"); } return Err(msg); } } private setJwtInfo() { let jwt = IsomorphicCookie.load("jwt"); if (jwt) { let jwtInfo: JwtInfo = { jwt, claims: jwt_decode(jwt) }; this.jwtInfo = Some(jwtInfo); this.jwtSub.next(this.jwtInfo); } } public static get Instance() { return this._instance || (this._instance = new this()); } }