convert api, appid, and token services to jslib
This commit is contained in:
parent
e1a513670f
commit
56bde82b41
|
@ -1,15 +1,21 @@
|
||||||
import { CipherType } from 'jslib/enums';
|
import { CipherType } from 'jslib/enums';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
ApiService,
|
||||||
|
AppIdService,
|
||||||
CryptoService,
|
CryptoService,
|
||||||
|
TokenService,
|
||||||
UtilsService,
|
UtilsService,
|
||||||
} from 'jslib/services';
|
} from 'jslib/services';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
ApiService as ApiServiceAbstraction,
|
||||||
|
AppIdService as AppIdServiceAbstraction,
|
||||||
CryptoService as CryptoServiceAbstraction,
|
CryptoService as CryptoServiceAbstraction,
|
||||||
MessagingService as MessagingServiceAbstraction,
|
MessagingService as MessagingServiceAbstraction,
|
||||||
PlatformUtilsService as PlatformUtilsServiceAbstraction,
|
PlatformUtilsService as PlatformUtilsServiceAbstraction,
|
||||||
StorageService as StorageServiceAbstraction,
|
StorageService as StorageServiceAbstraction,
|
||||||
|
TokenService as TokenServiceAbstraction,
|
||||||
UtilsService as UtilsServiceAbstraction,
|
UtilsService as UtilsServiceAbstraction,
|
||||||
} from 'jslib/abstractions';
|
} from 'jslib/abstractions';
|
||||||
|
|
||||||
|
@ -23,8 +29,6 @@ import TabsBackground from './tabs.background';
|
||||||
import WebRequestBackground from './webRequest.background';
|
import WebRequestBackground from './webRequest.background';
|
||||||
import WindowsBackground from './windows.background';
|
import WindowsBackground from './windows.background';
|
||||||
|
|
||||||
import ApiService from '../services/api.service';
|
|
||||||
import AppIdService from '../services/appId.service';
|
|
||||||
import AutofillService from '../services/autofill.service';
|
import AutofillService from '../services/autofill.service';
|
||||||
import BrowserMessagingService from '../services/browserMessaging.service';
|
import BrowserMessagingService from '../services/browserMessaging.service';
|
||||||
import BrowserPlatformUtilsService from '../services/browserPlatformUtils.service';
|
import BrowserPlatformUtilsService from '../services/browserPlatformUtils.service';
|
||||||
|
@ -40,7 +44,6 @@ import LockService from '../services/lock.service';
|
||||||
import PasswordGenerationService from '../services/passwordGeneration.service';
|
import PasswordGenerationService from '../services/passwordGeneration.service';
|
||||||
import SettingsService from '../services/settings.service';
|
import SettingsService from '../services/settings.service';
|
||||||
import SyncService from '../services/sync.service';
|
import SyncService from '../services/sync.service';
|
||||||
import TokenService from '../services/token.service';
|
|
||||||
import TotpService from '../services/totp.service';
|
import TotpService from '../services/totp.service';
|
||||||
import UserService from '../services/user.service';
|
import UserService from '../services/user.service';
|
||||||
|
|
||||||
|
@ -52,9 +55,9 @@ export default class MainBackground {
|
||||||
utilsService: UtilsServiceAbstraction;
|
utilsService: UtilsServiceAbstraction;
|
||||||
constantsService: ConstantsService;
|
constantsService: ConstantsService;
|
||||||
cryptoService: CryptoServiceAbstraction;
|
cryptoService: CryptoServiceAbstraction;
|
||||||
tokenService: TokenService;
|
tokenService: TokenServiceAbstraction;
|
||||||
appIdService: AppIdService;
|
appIdService: AppIdServiceAbstraction;
|
||||||
apiService: ApiService;
|
apiService: ApiServiceAbstraction;
|
||||||
environmentService: EnvironmentService;
|
environmentService: EnvironmentService;
|
||||||
userService: UserService;
|
userService: UserService;
|
||||||
settingsService: SettingsService;
|
settingsService: SettingsService;
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
import { ApiService } from 'jslib/abstractions/api.service';
|
||||||
|
import { AppIdService } from 'jslib/abstractions/appId.service';
|
||||||
import { CryptoService } from 'jslib/abstractions/crypto.service';
|
import { CryptoService } from 'jslib/abstractions/crypto.service';
|
||||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||||
import { StorageService } from 'jslib/abstractions/storage.service';
|
import { StorageService } from 'jslib/abstractions/storage.service';
|
||||||
|
import { TokenService } from 'jslib/abstractions/token.service';
|
||||||
import { UtilsService } from 'jslib/abstractions/utils.service';
|
import { UtilsService } from 'jslib/abstractions/utils.service';
|
||||||
|
|
||||||
function getBackgroundService<T>(service: string) {
|
function getBackgroundService<T>(service: string) {
|
||||||
|
@ -11,10 +14,10 @@ function getBackgroundService<T>(service: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const storageService = getBackgroundService<StorageService>('storageService');
|
export const storageService = getBackgroundService<StorageService>('storageService');
|
||||||
export const tokenService = getBackgroundService<any>('tokenService');
|
export const tokenService = getBackgroundService<TokenService>('tokenService');
|
||||||
export const cryptoService = getBackgroundService<any>('cryptoService');
|
export const cryptoService = getBackgroundService<any>('cryptoService');
|
||||||
export const userService = getBackgroundService<any>('userService');
|
export const userService = getBackgroundService<any>('userService');
|
||||||
export const apiService = getBackgroundService<any>('apiService');
|
export const apiService = getBackgroundService<ApiService>('apiService');
|
||||||
export const folderService = getBackgroundService<any>('folderService');
|
export const folderService = getBackgroundService<any>('folderService');
|
||||||
export const cipherService = getBackgroundService<CryptoService>('cipherService');
|
export const cipherService = getBackgroundService<CryptoService>('cipherService');
|
||||||
export const syncService = getBackgroundService<any>('syncService');
|
export const syncService = getBackgroundService<any>('syncService');
|
||||||
|
@ -22,7 +25,7 @@ export const autofillService = getBackgroundService<any>('autofillService');
|
||||||
export const passwordGenerationService = getBackgroundService<any>('passwordGenerationService');
|
export const passwordGenerationService = getBackgroundService<any>('passwordGenerationService');
|
||||||
export const platformUtilsService = getBackgroundService<PlatformUtilsService>('platformUtilsService');
|
export const platformUtilsService = getBackgroundService<PlatformUtilsService>('platformUtilsService');
|
||||||
export const utilsService = getBackgroundService<UtilsService>('utilsService');
|
export const utilsService = getBackgroundService<UtilsService>('utilsService');
|
||||||
export const appIdService = getBackgroundService<any>('appIdService');
|
export const appIdService = getBackgroundService<AppIdService>('appIdService');
|
||||||
export const i18nService = getBackgroundService<any>('i18nService');
|
export const i18nService = getBackgroundService<any>('i18nService');
|
||||||
export const constantsService = getBackgroundService<any>('constantsService');
|
export const constantsService = getBackgroundService<any>('constantsService');
|
||||||
export const settingsService = getBackgroundService<any>('settingsService');
|
export const settingsService = getBackgroundService<any>('settingsService');
|
||||||
|
|
|
@ -1,461 +0,0 @@
|
||||||
import AppIdService from './appId.service';
|
|
||||||
import ConstantsService from './constants.service';
|
|
||||||
import TokenService from './token.service';
|
|
||||||
|
|
||||||
import { PlatformUtilsService } from 'jslib/abstractions';
|
|
||||||
|
|
||||||
import { EnvironmentUrls } from 'jslib/models/domain';
|
|
||||||
|
|
||||||
import {
|
|
||||||
CipherRequest,
|
|
||||||
DeviceRequest,
|
|
||||||
DeviceTokenRequest,
|
|
||||||
FolderRequest,
|
|
||||||
PasswordHintRequest,
|
|
||||||
RegisterRequest,
|
|
||||||
TokenRequest,
|
|
||||||
TwoFactorEmailRequest,
|
|
||||||
} from 'jslib/models/request';
|
|
||||||
|
|
||||||
import {
|
|
||||||
AttachmentResponse,
|
|
||||||
CipherResponse,
|
|
||||||
DeviceResponse,
|
|
||||||
DomainsResponse,
|
|
||||||
ErrorResponse,
|
|
||||||
FolderResponse,
|
|
||||||
GlobalDomainResponse,
|
|
||||||
IdentityTokenResponse,
|
|
||||||
KeysResponse,
|
|
||||||
ListResponse,
|
|
||||||
ProfileOrganizationResponse,
|
|
||||||
ProfileResponse,
|
|
||||||
SyncResponse,
|
|
||||||
} from 'jslib/models/response';
|
|
||||||
|
|
||||||
export default class ApiService {
|
|
||||||
urlsSet: boolean = false;
|
|
||||||
baseUrl: string;
|
|
||||||
identityBaseUrl: string;
|
|
||||||
deviceType: string;
|
|
||||||
logoutCallback: Function;
|
|
||||||
|
|
||||||
constructor(private tokenService: TokenService, platformUtilsService: PlatformUtilsService,
|
|
||||||
logoutCallback: Function) {
|
|
||||||
this.logoutCallback = logoutCallback;
|
|
||||||
this.deviceType = platformUtilsService.getDevice().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
setUrls(urls: EnvironmentUrls) {
|
|
||||||
this.urlsSet = true;
|
|
||||||
|
|
||||||
if (urls.base != null) {
|
|
||||||
this.baseUrl = urls.base + '/api';
|
|
||||||
this.identityBaseUrl = urls.base + '/identity';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (urls.api != null && urls.identity != null) {
|
|
||||||
this.baseUrl = urls.api;
|
|
||||||
this.identityBaseUrl = urls.identity;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* tslint:disable */
|
|
||||||
// Desktop
|
|
||||||
//this.baseUrl = 'http://localhost:4000';
|
|
||||||
//this.identityBaseUrl = 'http://localhost:33656';
|
|
||||||
|
|
||||||
// Desktop HTTPS
|
|
||||||
//this.baseUrl = 'https://localhost:44377';
|
|
||||||
//this.identityBaseUrl = 'https://localhost:44392';
|
|
||||||
|
|
||||||
// Desktop external
|
|
||||||
//this.baseUrl = 'http://192.168.1.3:4000';
|
|
||||||
//this.identityBaseUrl = 'http://192.168.1.3:33656';
|
|
||||||
|
|
||||||
// Preview
|
|
||||||
//this.baseUrl = 'https://preview-api.bitwarden.com';
|
|
||||||
//this.identityBaseUrl = 'https://preview-identity.bitwarden.com';
|
|
||||||
|
|
||||||
// Production
|
|
||||||
this.baseUrl = 'https://api.bitwarden.com';
|
|
||||||
this.identityBaseUrl = 'https://identity.bitwarden.com';
|
|
||||||
/* tslint:enable */
|
|
||||||
}
|
|
||||||
|
|
||||||
// Auth APIs
|
|
||||||
|
|
||||||
async postIdentityToken(request: TokenRequest): Promise<IdentityTokenResponse | any> {
|
|
||||||
const response = await fetch(new Request(this.identityBaseUrl + '/connect/token', {
|
|
||||||
body: this.qsStringify(request.toIdentityToken()),
|
|
||||||
cache: 'no-cache',
|
|
||||||
headers: new Headers({
|
|
||||||
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
|
|
||||||
'Accept': 'application/json',
|
|
||||||
'Device-Type': this.deviceType,
|
|
||||||
}),
|
|
||||||
method: 'POST',
|
|
||||||
}));
|
|
||||||
|
|
||||||
let responseJson: any = null;
|
|
||||||
const typeHeader = response.headers.get('content-type');
|
|
||||||
if (typeHeader != null && typeHeader.indexOf('application/json') > -1) {
|
|
||||||
responseJson = await response.json();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (responseJson != null) {
|
|
||||||
if (response.status === 200) {
|
|
||||||
return new IdentityTokenResponse(responseJson);
|
|
||||||
} else if (response.status === 400 && responseJson.TwoFactorProviders2 &&
|
|
||||||
Object.keys(responseJson.TwoFactorProviders2).length) {
|
|
||||||
await this.tokenService.clearTwoFactorToken(request.email);
|
|
||||||
return responseJson.TwoFactorProviders2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.reject(new ErrorResponse(responseJson, response.status, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
async refreshIdentityToken(): Promise<any> {
|
|
||||||
try {
|
|
||||||
await this.doRefreshToken();
|
|
||||||
} catch (e) {
|
|
||||||
return Promise.reject(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Two Factor APIs
|
|
||||||
|
|
||||||
async postTwoFactorEmail(request: TwoFactorEmailRequest): Promise<any> {
|
|
||||||
const response = await fetch(new Request(this.baseUrl + '/two-factor/send-email-login', {
|
|
||||||
body: JSON.stringify(request),
|
|
||||||
cache: 'no-cache',
|
|
||||||
headers: new Headers({
|
|
||||||
'Content-Type': 'application/json; charset=utf-8',
|
|
||||||
'Device-Type': this.deviceType,
|
|
||||||
}),
|
|
||||||
method: 'POST',
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (response.status !== 200) {
|
|
||||||
const error = await this.handleError(response, false);
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Account APIs
|
|
||||||
|
|
||||||
async getAccountRevisionDate(): Promise<number> {
|
|
||||||
const authHeader = await this.handleTokenState();
|
|
||||||
const response = await fetch(new Request(this.baseUrl + '/accounts/revision-date', {
|
|
||||||
cache: 'no-cache',
|
|
||||||
headers: new Headers({
|
|
||||||
'Accept': 'application/json',
|
|
||||||
'Authorization': authHeader,
|
|
||||||
'Device-Type': this.deviceType,
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (response.status === 200) {
|
|
||||||
return (await response.json() as number);
|
|
||||||
} else {
|
|
||||||
const error = await this.handleError(response, false);
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async postPasswordHint(request: PasswordHintRequest): Promise<any> {
|
|
||||||
const response = await fetch(new Request(this.baseUrl + '/accounts/password-hint', {
|
|
||||||
body: JSON.stringify(request),
|
|
||||||
cache: 'no-cache',
|
|
||||||
headers: new Headers({
|
|
||||||
'Content-Type': 'application/json; charset=utf-8',
|
|
||||||
'Device-Type': this.deviceType,
|
|
||||||
}),
|
|
||||||
method: 'POST',
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (response.status !== 200) {
|
|
||||||
const error = await this.handleError(response, false);
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async postRegister(request: RegisterRequest): Promise<any> {
|
|
||||||
const response = await fetch(new Request(this.baseUrl + '/accounts/register', {
|
|
||||||
body: JSON.stringify(request),
|
|
||||||
cache: 'no-cache',
|
|
||||||
headers: new Headers({
|
|
||||||
'Content-Type': 'application/json; charset=utf-8',
|
|
||||||
'Device-Type': this.deviceType,
|
|
||||||
}),
|
|
||||||
method: 'POST',
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (response.status !== 200) {
|
|
||||||
const error = await this.handleError(response, false);
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Folder APIs
|
|
||||||
|
|
||||||
async postFolder(request: FolderRequest): Promise<FolderResponse> {
|
|
||||||
const authHeader = await this.handleTokenState();
|
|
||||||
const response = await fetch(new Request(this.baseUrl + '/folders', {
|
|
||||||
body: JSON.stringify(request),
|
|
||||||
cache: 'no-cache',
|
|
||||||
headers: new Headers({
|
|
||||||
'Accept': 'application/json',
|
|
||||||
'Authorization': authHeader,
|
|
||||||
'Content-Type': 'application/json; charset=utf-8',
|
|
||||||
'Device-Type': this.deviceType,
|
|
||||||
}),
|
|
||||||
method: 'POST',
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (response.status === 200) {
|
|
||||||
const responseJson = await response.json();
|
|
||||||
return new FolderResponse(responseJson);
|
|
||||||
} else {
|
|
||||||
const error = await this.handleError(response, false);
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async putFolder(id: string, request: FolderRequest): Promise<FolderResponse> {
|
|
||||||
const authHeader = await this.handleTokenState();
|
|
||||||
const response = await fetch(new Request(this.baseUrl + '/folders/' + id, {
|
|
||||||
body: JSON.stringify(request),
|
|
||||||
cache: 'no-cache',
|
|
||||||
headers: new Headers({
|
|
||||||
'Accept': 'application/json',
|
|
||||||
'Authorization': authHeader,
|
|
||||||
'Content-Type': 'application/json; charset=utf-8',
|
|
||||||
'Device-Type': this.deviceType,
|
|
||||||
}),
|
|
||||||
method: 'PUT',
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (response.status === 200) {
|
|
||||||
const responseJson = await response.json();
|
|
||||||
return new FolderResponse(responseJson);
|
|
||||||
} else {
|
|
||||||
const error = await this.handleError(response, false);
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async deleteFolder(id: string): Promise<any> {
|
|
||||||
const authHeader = await this.handleTokenState();
|
|
||||||
const response = await fetch(new Request(this.baseUrl + '/folders/' + id, {
|
|
||||||
cache: 'no-cache',
|
|
||||||
headers: new Headers({
|
|
||||||
'Authorization': authHeader,
|
|
||||||
'Device-Type': this.deviceType,
|
|
||||||
}),
|
|
||||||
method: 'DELETE',
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (response.status !== 200) {
|
|
||||||
const error = await this.handleError(response, false);
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cipher APIs
|
|
||||||
|
|
||||||
async postCipher(request: CipherRequest): Promise<CipherResponse> {
|
|
||||||
const authHeader = await this.handleTokenState();
|
|
||||||
const response = await fetch(new Request(this.baseUrl + '/ciphers', {
|
|
||||||
body: JSON.stringify(request),
|
|
||||||
cache: 'no-cache',
|
|
||||||
headers: new Headers({
|
|
||||||
'Accept': 'application/json',
|
|
||||||
'Authorization': authHeader,
|
|
||||||
'Content-Type': 'application/json; charset=utf-8',
|
|
||||||
'Device-Type': this.deviceType,
|
|
||||||
}),
|
|
||||||
method: 'POST',
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (response.status === 200) {
|
|
||||||
const responseJson = await response.json();
|
|
||||||
return new CipherResponse(responseJson);
|
|
||||||
} else {
|
|
||||||
const error = await this.handleError(response, false);
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async putCipher(id: string, request: CipherRequest): Promise<CipherResponse> {
|
|
||||||
const authHeader = await this.handleTokenState();
|
|
||||||
const response = await fetch(new Request(this.baseUrl + '/ciphers/' + id, {
|
|
||||||
body: JSON.stringify(request),
|
|
||||||
cache: 'no-cache',
|
|
||||||
headers: new Headers({
|
|
||||||
'Accept': 'application/json',
|
|
||||||
'Authorization': authHeader,
|
|
||||||
'Content-Type': 'application/json; charset=utf-8',
|
|
||||||
'Device-Type': this.deviceType,
|
|
||||||
}),
|
|
||||||
method: 'PUT',
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (response.status === 200) {
|
|
||||||
const responseJson = await response.json();
|
|
||||||
return new CipherResponse(responseJson);
|
|
||||||
} else {
|
|
||||||
const error = await this.handleError(response, false);
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async deleteCipher(id: string): Promise<any> {
|
|
||||||
const authHeader = await this.handleTokenState();
|
|
||||||
const response = await fetch(new Request(this.baseUrl + '/ciphers/' + id, {
|
|
||||||
cache: 'no-cache',
|
|
||||||
headers: new Headers({
|
|
||||||
'Authorization': authHeader,
|
|
||||||
'Device-Type': this.deviceType,
|
|
||||||
}),
|
|
||||||
method: 'DELETE',
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (response.status !== 200) {
|
|
||||||
const error = await this.handleError(response, false);
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attachments APIs
|
|
||||||
|
|
||||||
async postCipherAttachment(id: string, data: FormData): Promise<CipherResponse> {
|
|
||||||
const authHeader = await this.handleTokenState();
|
|
||||||
const response = await fetch(new Request(this.baseUrl + '/ciphers/' + id + '/attachment', {
|
|
||||||
body: data,
|
|
||||||
cache: 'no-cache',
|
|
||||||
headers: new Headers({
|
|
||||||
'Accept': 'application/json',
|
|
||||||
'Authorization': authHeader,
|
|
||||||
'Device-Type': this.deviceType,
|
|
||||||
}),
|
|
||||||
method: 'POST',
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (response.status === 200) {
|
|
||||||
const responseJson = await response.json();
|
|
||||||
return new CipherResponse(responseJson);
|
|
||||||
} else {
|
|
||||||
const error = await this.handleError(response, false);
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async deleteCipherAttachment(id: string, attachmentId: string): Promise<any> {
|
|
||||||
const authHeader = await this.handleTokenState();
|
|
||||||
const response = await fetch(new Request(this.baseUrl + '/ciphers/' + id + '/attachment/' + attachmentId, {
|
|
||||||
cache: 'no-cache',
|
|
||||||
headers: new Headers({
|
|
||||||
'Authorization': authHeader,
|
|
||||||
'Device-Type': this.deviceType,
|
|
||||||
}),
|
|
||||||
method: 'DELETE',
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (response.status !== 200) {
|
|
||||||
const error = await this.handleError(response, false);
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync APIs
|
|
||||||
|
|
||||||
async getSync(): Promise<SyncResponse> {
|
|
||||||
const authHeader = await this.handleTokenState();
|
|
||||||
const response = await fetch(new Request(this.baseUrl + '/sync', {
|
|
||||||
cache: 'no-cache',
|
|
||||||
headers: new Headers({
|
|
||||||
'Accept': 'application/json',
|
|
||||||
'Authorization': authHeader,
|
|
||||||
'Device-Type': this.deviceType,
|
|
||||||
}),
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (response.status === 200) {
|
|
||||||
const responseJson = await response.json();
|
|
||||||
return new SyncResponse(responseJson);
|
|
||||||
} else {
|
|
||||||
const error = await this.handleError(response, false);
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helpers
|
|
||||||
|
|
||||||
private async handleError(response: Response, tokenError: boolean): Promise<ErrorResponse> {
|
|
||||||
if ((tokenError && response.status === 400) || response.status === 401 || response.status === 403) {
|
|
||||||
this.logoutCallback(true);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
let responseJson: any = null;
|
|
||||||
const typeHeader = response.headers.get('content-type');
|
|
||||||
if (typeHeader != null && typeHeader.indexOf('application/json') > -1) {
|
|
||||||
responseJson = await response.json();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ErrorResponse(responseJson, response.status, tokenError);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async handleTokenState(): Promise<string> {
|
|
||||||
let accessToken: string;
|
|
||||||
if (this.tokenService.tokenNeedsRefresh()) {
|
|
||||||
const tokenResponse = await this.doRefreshToken();
|
|
||||||
accessToken = tokenResponse.accessToken;
|
|
||||||
} else {
|
|
||||||
accessToken = await this.tokenService.getToken();
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'Bearer ' + accessToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async doRefreshToken(): Promise<IdentityTokenResponse> {
|
|
||||||
const refreshToken = await this.tokenService.getRefreshToken();
|
|
||||||
if (refreshToken == null || refreshToken === '') {
|
|
||||||
throw new Error();
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetch(new Request(this.identityBaseUrl + '/connect/token', {
|
|
||||||
body: this.qsStringify({
|
|
||||||
grant_type: 'refresh_token',
|
|
||||||
client_id: 'browser',
|
|
||||||
refresh_token: refreshToken,
|
|
||||||
}),
|
|
||||||
cache: 'no-cache',
|
|
||||||
headers: new Headers({
|
|
||||||
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
|
|
||||||
'Accept': 'application/json',
|
|
||||||
'Device-Type': this.deviceType,
|
|
||||||
}),
|
|
||||||
method: 'POST',
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (response.status === 200) {
|
|
||||||
const responseJson = await response.json();
|
|
||||||
const tokenResponse = new IdentityTokenResponse(responseJson);
|
|
||||||
await this.tokenService.setTokens(tokenResponse.accessToken, tokenResponse.refreshToken);
|
|
||||||
return tokenResponse;
|
|
||||||
} else {
|
|
||||||
const error = await this.handleError(response, true);
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private qsStringify(params: any): string {
|
|
||||||
return Object.keys(params).map((key) => {
|
|
||||||
return encodeURIComponent(key) + '=' + encodeURIComponent(params[key]);
|
|
||||||
}).join('&');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
import { UtilsService } from 'jslib/services';
|
|
||||||
|
|
||||||
import { StorageService } from 'jslib/abstractions';
|
|
||||||
|
|
||||||
export default class AppIdService {
|
|
||||||
constructor(private storageService: StorageService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
getAppId(): Promise<string> {
|
|
||||||
return this.makeAndGetAppId('appId');
|
|
||||||
}
|
|
||||||
|
|
||||||
getAnonymousAppId(): Promise<string> {
|
|
||||||
return this.makeAndGetAppId('anonymousAppId');
|
|
||||||
}
|
|
||||||
|
|
||||||
private async makeAndGetAppId(key: string) {
|
|
||||||
const existingId = await this.storageService.get<string>(key);
|
|
||||||
if (existingId != null) {
|
|
||||||
return existingId;
|
|
||||||
}
|
|
||||||
|
|
||||||
const guid = UtilsService.newGuid();
|
|
||||||
await this.storageService.save(key, guid);
|
|
||||||
return guid;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -8,13 +8,13 @@ import AutofillPageDetails from '../models/domain/autofillPageDetails';
|
||||||
import AutofillScript from '../models/domain/autofillScript';
|
import AutofillScript from '../models/domain/autofillScript';
|
||||||
|
|
||||||
import CipherService from './cipher.service';
|
import CipherService from './cipher.service';
|
||||||
import TokenService from './token.service';
|
|
||||||
import TotpService from './totp.service';
|
import TotpService from './totp.service';
|
||||||
|
|
||||||
import { UtilsService } from 'jslib/services';
|
import { UtilsService } from 'jslib/services';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
PlatformUtilsService,
|
PlatformUtilsService,
|
||||||
|
TokenService,
|
||||||
UtilsService as UtilsServiceAbstraction,
|
UtilsService as UtilsServiceAbstraction,
|
||||||
} from 'jslib/abstractions';
|
} from 'jslib/abstractions';
|
||||||
|
|
||||||
|
|
|
@ -17,11 +17,11 @@ import {
|
||||||
} from 'jslib/models/response';
|
} from 'jslib/models/response';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
ApiService,
|
||||||
CryptoService,
|
CryptoService,
|
||||||
StorageService,
|
StorageService,
|
||||||
} from 'jslib/abstractions';
|
} from 'jslib/abstractions';
|
||||||
|
|
||||||
import ApiService from './api.service';
|
|
||||||
import ConstantsService from './constants.service';
|
import ConstantsService from './constants.service';
|
||||||
import SettingsService from './settings.service';
|
import SettingsService from './settings.service';
|
||||||
import UserService from './user.service';
|
import UserService from './user.service';
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import ApiService from './api.service';
|
|
||||||
import ConstantsService from './constants.service';
|
import ConstantsService from './constants.service';
|
||||||
|
|
||||||
import { EnvironmentUrls } from 'jslib/models/domain';
|
import { EnvironmentUrls } from 'jslib/models/domain';
|
||||||
|
|
||||||
import { StorageService } from 'jslib/abstractions';
|
import {
|
||||||
|
ApiService,
|
||||||
|
StorageService,
|
||||||
|
} from 'jslib/abstractions';
|
||||||
|
|
||||||
export default class EnvironmentService {
|
export default class EnvironmentService {
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import ApiService from './api.service';
|
|
||||||
import UserService from './user.service';
|
import UserService from './user.service';
|
||||||
|
|
||||||
import { FolderData } from 'jslib/models/data';
|
import { FolderData } from 'jslib/models/data';
|
||||||
|
@ -10,6 +9,7 @@ import { FolderRequest } from 'jslib/models/request';
|
||||||
import { FolderResponse } from 'jslib/models/response';
|
import { FolderResponse } from 'jslib/models/response';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
ApiService,
|
||||||
CryptoService,
|
CryptoService,
|
||||||
StorageService,
|
StorageService,
|
||||||
} from 'jslib/abstractions';
|
} from 'jslib/abstractions';
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import ApiService from './api.service';
|
|
||||||
import CipherService from './cipher.service';
|
import CipherService from './cipher.service';
|
||||||
import CollectionService from './collection.service';
|
import CollectionService from './collection.service';
|
||||||
import FolderService from './folder.service';
|
import FolderService from './folder.service';
|
||||||
|
@ -6,6 +5,7 @@ import SettingsService from './settings.service';
|
||||||
import UserService from './user.service';
|
import UserService from './user.service';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
ApiService,
|
||||||
CryptoService,
|
CryptoService,
|
||||||
MessagingService,
|
MessagingService,
|
||||||
StorageService,
|
StorageService,
|
||||||
|
|
|
@ -1,176 +0,0 @@
|
||||||
import ConstantsService from './constants.service';
|
|
||||||
|
|
||||||
import { UtilsService } from 'jslib/services/utils.service';
|
|
||||||
|
|
||||||
import { StorageService } from 'jslib/abstractions';
|
|
||||||
|
|
||||||
const Keys = {
|
|
||||||
accessToken: 'accessToken',
|
|
||||||
refreshToken: 'refreshToken',
|
|
||||||
twoFactorTokenPrefix: 'twoFactorToken_',
|
|
||||||
};
|
|
||||||
|
|
||||||
export default class TokenService {
|
|
||||||
token: string;
|
|
||||||
decodedToken: any;
|
|
||||||
refreshToken: string;
|
|
||||||
|
|
||||||
constructor(private storageService: StorageService) {
|
|
||||||
}
|
|
||||||
|
|
||||||
setTokens(accessToken: string, refreshToken: string): Promise<any> {
|
|
||||||
return Promise.all([
|
|
||||||
this.setToken(accessToken),
|
|
||||||
this.setRefreshToken(refreshToken),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
setToken(token: string): Promise<any> {
|
|
||||||
this.token = token;
|
|
||||||
this.decodedToken = null;
|
|
||||||
return this.storageService.save(Keys.accessToken, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getToken(): Promise<string> {
|
|
||||||
if (this.token != null) {
|
|
||||||
return this.token;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.token = await this.storageService.get<string>(Keys.accessToken);
|
|
||||||
return this.token;
|
|
||||||
}
|
|
||||||
|
|
||||||
setRefreshToken(refreshToken: string): Promise<any> {
|
|
||||||
this.refreshToken = refreshToken;
|
|
||||||
return this.storageService.save(Keys.refreshToken, refreshToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getRefreshToken(): Promise<string> {
|
|
||||||
if (this.refreshToken != null) {
|
|
||||||
return this.refreshToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.refreshToken = await this.storageService.get<string>(Keys.refreshToken);
|
|
||||||
return this.refreshToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
setTwoFactorToken(token: string, email: string): Promise<any> {
|
|
||||||
return this.storageService.save(Keys.twoFactorTokenPrefix + email, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
getTwoFactorToken(email: string): Promise<string> {
|
|
||||||
return this.storageService.get<string>(Keys.twoFactorTokenPrefix + email);
|
|
||||||
}
|
|
||||||
|
|
||||||
clearTwoFactorToken(email: string): Promise<any> {
|
|
||||||
return this.storageService.remove(Keys.twoFactorTokenPrefix + email);
|
|
||||||
}
|
|
||||||
|
|
||||||
clearToken(): Promise<any> {
|
|
||||||
this.token = null;
|
|
||||||
this.decodedToken = null;
|
|
||||||
this.refreshToken = null;
|
|
||||||
|
|
||||||
return Promise.all([
|
|
||||||
this.storageService.remove(Keys.accessToken),
|
|
||||||
this.storageService.remove(Keys.refreshToken),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// jwthelper methods
|
|
||||||
// ref https://github.com/auth0/angular-jwt/blob/master/src/angularJwt/services/jwt.js
|
|
||||||
|
|
||||||
decodeToken(): any {
|
|
||||||
if (this.decodedToken) {
|
|
||||||
return this.decodedToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.token == null) {
|
|
||||||
throw new Error('Token not found.');
|
|
||||||
}
|
|
||||||
|
|
||||||
const parts = this.token.split('.');
|
|
||||||
if (parts.length !== 3) {
|
|
||||||
throw new Error('JWT must have 3 parts');
|
|
||||||
}
|
|
||||||
|
|
||||||
const decoded = UtilsService.urlBase64Decode(parts[1]);
|
|
||||||
if (decoded == null) {
|
|
||||||
throw new Error('Cannot decode the token');
|
|
||||||
}
|
|
||||||
|
|
||||||
this.decodedToken = JSON.parse(decoded);
|
|
||||||
return this.decodedToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
getTokenExpirationDate(): Date {
|
|
||||||
const decoded = this.decodeToken();
|
|
||||||
if (typeof decoded.exp === 'undefined') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const d = new Date(0); // The 0 here is the key, which sets the date to the epoch
|
|
||||||
d.setUTCSeconds(decoded.exp);
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenSecondsRemaining(offsetSeconds: number = 0): number {
|
|
||||||
const d = this.getTokenExpirationDate();
|
|
||||||
if (d == null) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const msRemaining = d.valueOf() - (new Date().valueOf() + (offsetSeconds * 1000));
|
|
||||||
return Math.round(msRemaining / 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenNeedsRefresh(minutes: number = 5): boolean {
|
|
||||||
const sRemaining = this.tokenSecondsRemaining();
|
|
||||||
return sRemaining < (60 * minutes);
|
|
||||||
}
|
|
||||||
|
|
||||||
getUserId(): string {
|
|
||||||
const decoded = this.decodeToken();
|
|
||||||
if (typeof decoded.sub === 'undefined') {
|
|
||||||
throw new Error('No user id found');
|
|
||||||
}
|
|
||||||
|
|
||||||
return decoded.sub as string;
|
|
||||||
}
|
|
||||||
|
|
||||||
getEmail(): string {
|
|
||||||
const decoded = this.decodeToken();
|
|
||||||
if (typeof decoded.email === 'undefined') {
|
|
||||||
throw new Error('No email found');
|
|
||||||
}
|
|
||||||
|
|
||||||
return decoded.email as string;
|
|
||||||
}
|
|
||||||
|
|
||||||
getName(): string {
|
|
||||||
const decoded = this.decodeToken();
|
|
||||||
if (typeof decoded.name === 'undefined') {
|
|
||||||
throw new Error('No name found');
|
|
||||||
}
|
|
||||||
|
|
||||||
return decoded.name as string;
|
|
||||||
}
|
|
||||||
|
|
||||||
getPremium(): boolean {
|
|
||||||
const decoded = this.decodeToken();
|
|
||||||
if (typeof decoded.premium === 'undefined') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return decoded.premium as boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
getIssuer(): string {
|
|
||||||
const decoded = this.decodeToken();
|
|
||||||
if (typeof decoded.iss === 'undefined') {
|
|
||||||
throw new Error('No issuer found');
|
|
||||||
}
|
|
||||||
|
|
||||||
return decoded.iss as string;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,4 @@
|
||||||
import TokenService from './token.service';
|
import { StorageService, TokenService } from 'jslib/abstractions';
|
||||||
|
|
||||||
import { StorageService } from 'jslib/abstractions';
|
|
||||||
|
|
||||||
const Keys = {
|
const Keys = {
|
||||||
userId: 'userId',
|
userId: 'userId',
|
||||||
|
|
Loading…
Reference in New Issue