bitwarden-estensione-browser/src/services/api.service.ts

837 lines
32 KiB
TypeScript
Raw Normal View History

2018-06-13 20:08:43 +02:00
import { DeviceType } from '../enums/deviceType';
2018-01-09 22:19:55 +01:00
import { ApiService as ApiServiceAbstraction } from '../abstractions/api.service';
import { PlatformUtilsService } from '../abstractions/platformUtils.service';
import { TokenService } from '../abstractions/token.service';
import { EnvironmentUrls } from '../models/domain/environmentUrls';
2018-06-12 23:12:27 +02:00
import { CipherBulkDeleteRequest } from '../models/request/cipherBulkDeleteRequest';
import { CipherBulkMoveRequest } from '../models/request/cipherBulkMoveRequest';
2018-06-13 06:02:15 +02:00
import { CipherBulkShareRequest } from '../models/request/cipherBulkShareRequest';
2018-06-12 19:07:06 +02:00
import { CipherCollectionsRequest } from '../models/request/cipherCollectionsRequest';
import { CipherRequest } from '../models/request/cipherRequest';
2018-06-12 17:45:02 +02:00
import { CipherShareRequest } from '../models/request/cipherShareRequest';
import { EmailRequest } from '../models/request/emailRequest';
import { EmailTokenRequest } from '../models/request/emailTokenRequest';
import { FolderRequest } from '../models/request/folderRequest';
2018-06-23 21:41:22 +02:00
import { ImportCiphersRequest } from '../models/request/importCiphersRequest';
import { ImportDirectoryRequest } from '../models/request/importDirectoryRequest';
2018-06-23 21:41:22 +02:00
import { ImportOrganizationCiphersRequest } from '../models/request/importOrganizationCiphersRequest';
import { PasswordHintRequest } from '../models/request/passwordHintRequest';
import { PasswordRequest } from '../models/request/passwordRequest';
2018-06-21 23:15:43 +02:00
import { PasswordVerificationRequest } from '../models/request/passwordVerificationRequest';
import { RegisterRequest } from '../models/request/registerRequest';
import { TokenRequest } from '../models/request/tokenRequest';
import { TwoFactorEmailRequest } from '../models/request/twoFactorEmailRequest';
2018-06-21 05:40:59 +02:00
import { UpdateProfileRequest } from '../models/request/updateProfileRequest';
import { CipherResponse } from '../models/response/cipherResponse';
import { ErrorResponse } from '../models/response/errorResponse';
import { FolderResponse } from '../models/response/folderResponse';
import { IdentityTokenResponse } from '../models/response/identityTokenResponse';
import { IdentityTwoFactorResponse } from '../models/response/identityTwoFactorResponse';
2018-05-03 18:46:49 +02:00
import { ProfileResponse } from '../models/response/profileResponse';
import { SyncResponse } from '../models/response/syncResponse';
2018-01-09 22:19:55 +01:00
2018-01-31 20:27:11 +01:00
export class ApiService implements ApiServiceAbstraction {
2018-01-09 22:19:55 +01:00
urlsSet: boolean = false;
2018-06-14 04:12:23 +02:00
apiBaseUrl: string;
identityBaseUrl: string;
2018-06-14 04:09:47 +02:00
private deviceType: string;
private isWebClient = false;
private usingBaseUrl = false;
2018-01-09 22:19:55 +01:00
2018-03-21 16:19:05 +01:00
constructor(private tokenService: TokenService, private platformUtilsService: PlatformUtilsService,
2018-05-16 05:40:15 +02:00
private logoutCallback: (expired: boolean) => Promise<void>) {
2018-06-13 20:08:43 +02:00
const device = platformUtilsService.getDevice();
this.deviceType = device.toString();
this.isWebClient = device === DeviceType.Web;
2018-01-09 22:19:55 +01:00
}
2018-01-09 22:23:27 +01:00
setUrls(urls: EnvironmentUrls): void {
2018-01-09 22:19:55 +01:00
this.urlsSet = true;
if (urls.base != null) {
2018-06-05 21:45:19 +02:00
this.usingBaseUrl = true;
2018-06-14 04:09:47 +02:00
this.apiBaseUrl = urls.base + '/api';
2018-01-09 22:19:55 +01:00
this.identityBaseUrl = urls.base + '/identity';
return;
}
if (urls.api != null && urls.identity != null) {
2018-06-14 04:09:47 +02:00
this.apiBaseUrl = urls.api;
2018-01-09 22:19:55 +01:00
this.identityBaseUrl = urls.identity;
return;
}
/* tslint:disable */
2018-06-22 04:12:26 +02:00
// Local Dev
2018-06-14 04:09:47 +02:00
//this.apiBaseUrl = 'http://localhost:4000';
//this.identityBaseUrl = 'http://localhost:33656';
2018-01-09 22:19:55 +01:00
// Production
2018-06-22 04:12:26 +02:00
this.apiBaseUrl = 'https://api.bitwarden.com';
this.identityBaseUrl = 'https://identity.bitwarden.com';
2018-01-09 22:19:55 +01:00
/* tslint:enable */
}
// Auth APIs
2018-02-02 04:55:49 +01:00
async postIdentityToken(request: TokenRequest): Promise<IdentityTokenResponse | IdentityTwoFactorResponse> {
2018-01-09 22:19:55 +01:00
const response = await fetch(new Request(this.identityBaseUrl + '/connect/token', {
2018-03-21 16:19:05 +01:00
body: this.qsStringify(request.toIdentityToken(this.platformUtilsService.identityClientId)),
2018-06-05 21:45:19 +02:00
credentials: this.getCredentials(),
2018-01-09 22:19:55 +01:00
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);
2018-02-02 04:55:49 +01:00
return new IdentityTwoFactorResponse(responseJson);
2018-01-09 22:19:55 +01:00
}
}
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> {
2018-06-14 04:09:47 +02:00
const response = await fetch(new Request(this.apiBaseUrl + '/two-factor/send-email-login', {
2018-01-09 22:19:55 +01:00
body: JSON.stringify(request),
cache: 'no-cache',
2018-06-05 21:45:19 +02:00
credentials: this.getCredentials(),
2018-01-09 22:19:55 +01:00
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
2018-05-03 18:46:49 +02:00
async getProfile(): Promise<ProfileResponse> {
const authHeader = await this.handleTokenState();
2018-06-14 04:09:47 +02:00
const response = await fetch(new Request(this.apiBaseUrl + '/accounts/profile', {
2018-05-03 18:46:49 +02:00
cache: 'no-cache',
2018-06-05 21:45:19 +02:00
credentials: this.getCredentials(),
2018-05-03 18:46:49 +02:00
headers: new Headers({
'Accept': 'application/json',
'Authorization': authHeader,
'Device-Type': this.deviceType,
}),
}));
if (response.status === 200) {
const responseJson = await response.json();
return new ProfileResponse(responseJson);
} else {
const error = await this.handleError(response, false);
return Promise.reject(error);
}
}
2018-06-21 05:40:59 +02:00
async putProfile(request: UpdateProfileRequest): Promise<ProfileResponse> {
const authHeader = await this.handleTokenState();
const response = await fetch(new Request(this.apiBaseUrl + '/accounts/profile', {
body: JSON.stringify(request),
cache: 'no-cache',
credentials: this.getCredentials(),
headers: new Headers({
'Accept': 'application/json',
'Content-Type': 'application/json; charset=utf-8',
'Authorization': authHeader,
'Device-Type': this.deviceType,
}),
method: 'PUT',
}));
if (response.status === 200) {
const responseJson = await response.json();
return new ProfileResponse(responseJson);
} else {
const error = await this.handleError(response, false);
return Promise.reject(error);
}
}
async postEmailToken(request: EmailTokenRequest): Promise<any> {
const authHeader = await this.handleTokenState();
const response = await fetch(new Request(this.apiBaseUrl + '/accounts/email-token', {
body: JSON.stringify(request),
cache: 'no-cache',
credentials: this.getCredentials(),
headers: new Headers({
'Accept': 'application/json',
'Content-Type': 'application/json; charset=utf-8',
'Authorization': authHeader,
'Device-Type': this.deviceType,
}),
method: 'POST',
}));
if (response.status !== 200) {
const error = await this.handleError(response, false);
return Promise.reject(error);
}
}
async postEmail(request: EmailRequest): Promise<any> {
const authHeader = await this.handleTokenState();
const response = await fetch(new Request(this.apiBaseUrl + '/accounts/email', {
body: JSON.stringify(request),
cache: 'no-cache',
credentials: this.getCredentials(),
headers: new Headers({
'Accept': 'application/json',
'Content-Type': 'application/json; charset=utf-8',
'Authorization': authHeader,
'Device-Type': this.deviceType,
}),
method: 'POST',
}));
if (response.status !== 200) {
const error = await this.handleError(response, false);
return Promise.reject(error);
}
}
async postPassword(request: PasswordRequest): Promise<any> {
const authHeader = await this.handleTokenState();
const response = await fetch(new Request(this.apiBaseUrl + '/accounts/password', {
body: JSON.stringify(request),
cache: 'no-cache',
credentials: this.getCredentials(),
headers: new Headers({
'Accept': 'application/json',
'Content-Type': 'application/json; charset=utf-8',
'Authorization': authHeader,
'Device-Type': this.deviceType,
}),
method: 'POST',
}));
if (response.status !== 200) {
const error = await this.handleError(response, false);
return Promise.reject(error);
}
}
2018-06-21 23:15:43 +02:00
async postSecurityStamp(request: PasswordVerificationRequest): Promise<any> {
const authHeader = await this.handleTokenState();
const response = await fetch(new Request(this.apiBaseUrl + '/accounts/security-stamp', {
body: JSON.stringify(request),
cache: 'no-cache',
credentials: this.getCredentials(),
headers: new Headers({
'Accept': 'application/json',
'Content-Type': 'application/json; charset=utf-8',
'Authorization': authHeader,
'Device-Type': this.deviceType,
}),
method: 'POST',
}));
if (response.status !== 200) {
const error = await this.handleError(response, false);
return Promise.reject(error);
}
}
async postDeleteAccount(request: PasswordVerificationRequest): Promise<any> {
const authHeader = await this.handleTokenState();
const response = await fetch(new Request(this.apiBaseUrl + '/accounts/delete', {
body: JSON.stringify(request),
cache: 'no-cache',
credentials: this.getCredentials(),
headers: new Headers({
'Accept': 'application/json',
'Content-Type': 'application/json; charset=utf-8',
'Authorization': authHeader,
'Device-Type': this.deviceType,
}),
method: 'POST',
}));
if (response.status !== 200) {
const error = await this.handleError(response, false);
return Promise.reject(error);
}
}
2018-01-09 22:19:55 +01:00
async getAccountRevisionDate(): Promise<number> {
const authHeader = await this.handleTokenState();
2018-06-14 04:09:47 +02:00
const response = await fetch(new Request(this.apiBaseUrl + '/accounts/revision-date', {
2018-01-09 22:19:55 +01:00
cache: 'no-cache',
2018-06-05 21:45:19 +02:00
credentials: this.getCredentials(),
2018-01-09 22:19:55 +01:00
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> {
2018-06-14 04:09:47 +02:00
const response = await fetch(new Request(this.apiBaseUrl + '/accounts/password-hint', {
2018-01-09 22:19:55 +01:00
body: JSON.stringify(request),
cache: 'no-cache',
2018-06-05 21:45:19 +02:00
credentials: this.getCredentials(),
2018-01-09 22:19:55 +01:00
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> {
2018-06-14 04:09:47 +02:00
const response = await fetch(new Request(this.apiBaseUrl + '/accounts/register', {
2018-01-09 22:19:55 +01:00
body: JSON.stringify(request),
cache: 'no-cache',
2018-06-05 21:45:19 +02:00
credentials: this.getCredentials(),
2018-01-09 22:19:55 +01:00
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();
2018-06-14 04:09:47 +02:00
const response = await fetch(new Request(this.apiBaseUrl + '/folders', {
2018-01-09 22:19:55 +01:00
body: JSON.stringify(request),
cache: 'no-cache',
2018-06-05 21:45:19 +02:00
credentials: this.getCredentials(),
2018-01-09 22:19:55 +01:00
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();
2018-06-14 04:09:47 +02:00
const response = await fetch(new Request(this.apiBaseUrl + '/folders/' + id, {
2018-01-09 22:19:55 +01:00
body: JSON.stringify(request),
cache: 'no-cache',
2018-06-05 21:45:19 +02:00
credentials: this.getCredentials(),
2018-01-09 22:19:55 +01:00
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();
2018-06-14 04:09:47 +02:00
const response = await fetch(new Request(this.apiBaseUrl + '/folders/' + id, {
2018-01-09 22:19:55 +01:00
cache: 'no-cache',
2018-06-05 21:45:19 +02:00
credentials: this.getCredentials(),
2018-01-09 22:19:55 +01:00
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();
2018-06-14 04:09:47 +02:00
const response = await fetch(new Request(this.apiBaseUrl + '/ciphers', {
2018-01-09 22:19:55 +01:00
body: JSON.stringify(request),
cache: 'no-cache',
2018-06-05 21:45:19 +02:00
credentials: this.getCredentials(),
2018-01-09 22:19:55 +01:00
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();
2018-06-14 04:09:47 +02:00
const response = await fetch(new Request(this.apiBaseUrl + '/ciphers/' + id, {
2018-01-09 22:19:55 +01:00
body: JSON.stringify(request),
cache: 'no-cache',
2018-06-05 21:45:19 +02:00
credentials: this.getCredentials(),
2018-01-09 22:19:55 +01:00
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);
}
}
2018-06-12 19:07:06 +02:00
async deleteCipher(id: string): Promise<any> {
const authHeader = await this.handleTokenState();
2018-06-14 04:09:47 +02:00
const response = await fetch(new Request(this.apiBaseUrl + '/ciphers/' + id, {
2018-06-12 19:07:06 +02:00
cache: 'no-cache',
credentials: this.getCredentials(),
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);
}
}
2018-06-12 23:12:27 +02:00
async deleteManyCiphers(request: CipherBulkDeleteRequest): Promise<any> {
const authHeader = await this.handleTokenState();
2018-06-14 04:09:47 +02:00
const response = await fetch(new Request(this.apiBaseUrl + '/ciphers', {
2018-06-12 23:12:27 +02:00
body: JSON.stringify(request),
cache: 'no-cache',
credentials: this.getCredentials(),
headers: new Headers({
'Accept': 'application/json',
'Authorization': authHeader,
'Content-Type': 'application/json; charset=utf-8',
'Device-Type': this.deviceType,
}),
method: 'DELETE',
}));
if (response.status !== 200) {
const error = await this.handleError(response, false);
return Promise.reject(error);
}
}
async putMoveCiphers(request: CipherBulkMoveRequest): Promise<any> {
const authHeader = await this.handleTokenState();
2018-06-14 04:09:47 +02:00
const response = await fetch(new Request(this.apiBaseUrl + '/ciphers/move', {
2018-06-12 23:12:27 +02:00
body: JSON.stringify(request),
cache: 'no-cache',
credentials: this.getCredentials(),
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 error = await this.handleError(response, false);
return Promise.reject(error);
}
}
2018-06-12 19:07:06 +02:00
async putShareCipher(id: string, request: CipherShareRequest): Promise<any> {
2018-06-12 17:45:02 +02:00
const authHeader = await this.handleTokenState();
2018-06-14 04:09:47 +02:00
const response = await fetch(new Request(this.apiBaseUrl + '/ciphers/' + id + '/share', {
2018-06-12 17:45:02 +02:00
body: JSON.stringify(request),
cache: 'no-cache',
credentials: this.getCredentials(),
2018-06-13 06:02:15 +02:00
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 error = await this.handleError(response, false);
return Promise.reject(error);
}
}
async putShareCiphers(request: CipherBulkShareRequest): Promise<any> {
const authHeader = await this.handleTokenState();
2018-06-14 04:09:47 +02:00
const response = await fetch(new Request(this.apiBaseUrl + '/ciphers/share', {
2018-06-13 06:02:15 +02:00
body: JSON.stringify(request),
cache: 'no-cache',
credentials: this.getCredentials(),
2018-06-12 17:45:02 +02:00
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 error = await this.handleError(response, false);
return Promise.reject(error);
}
}
2018-06-12 19:07:06 +02:00
async putCipherCollections(id: string, request: CipherCollectionsRequest): Promise<any> {
2018-01-09 22:19:55 +01:00
const authHeader = await this.handleTokenState();
2018-06-14 04:09:47 +02:00
const response = await fetch(new Request(this.apiBaseUrl + '/ciphers/' + id + '/collections', {
2018-06-12 19:07:06 +02:00
body: JSON.stringify(request),
2018-01-09 22:19:55 +01:00
cache: 'no-cache',
2018-06-05 21:45:19 +02:00
credentials: this.getCredentials(),
2018-01-09 22:19:55 +01:00
headers: new Headers({
2018-06-12 19:07:06 +02:00
'Accept': 'application/json',
2018-01-09 22:19:55 +01:00
'Authorization': authHeader,
2018-06-12 19:07:06 +02:00
'Content-Type': 'application/json; charset=utf-8',
2018-01-09 22:19:55 +01:00
'Device-Type': this.deviceType,
}),
2018-06-12 19:07:06 +02:00
method: 'PUT',
2018-01-09 22:19:55 +01:00
}));
if (response.status !== 200) {
const error = await this.handleError(response, false);
return Promise.reject(error);
}
}
2018-06-21 23:15:43 +02:00
async postPurgeCiphers(request: PasswordVerificationRequest): Promise<any> {
const authHeader = await this.handleTokenState();
const response = await fetch(new Request(this.apiBaseUrl + '/ciphers/purge', {
body: JSON.stringify(request),
cache: 'no-cache',
credentials: this.getCredentials(),
headers: new Headers({
'Accept': 'application/json',
'Content-Type': 'application/json; charset=utf-8',
'Authorization': authHeader,
2018-06-23 21:41:22 +02:00
'Device-Type': this.deviceType,
}),
method: 'POST',
}));
if (response.status !== 200) {
const error = await this.handleError(response, false);
return Promise.reject(error);
}
}
async postImportCiphers(request: ImportCiphersRequest): Promise<any> {
const authHeader = await this.handleTokenState();
const response = await fetch(new Request(this.apiBaseUrl + '/ciphers/import', {
body: JSON.stringify(request),
cache: 'no-cache',
credentials: this.getCredentials(),
headers: new Headers({
'Accept': 'application/json',
'Content-Type': 'application/json; charset=utf-8',
'Authorization': authHeader,
'Device-Type': this.deviceType,
}),
method: 'POST',
}));
if (response.status !== 200) {
const error = await this.handleError(response, false);
return Promise.reject(error);
}
}
async postImportOrganizationCiphers(request: ImportOrganizationCiphersRequest): Promise<any> {
const authHeader = await this.handleTokenState();
const response = await fetch(new Request(this.apiBaseUrl + '/ciphers/import-organization', {
body: JSON.stringify(request),
cache: 'no-cache',
credentials: this.getCredentials(),
headers: new Headers({
'Accept': 'application/json',
'Content-Type': 'application/json; charset=utf-8',
'Authorization': authHeader,
2018-06-21 23:15:43 +02:00
'Device-Type': this.deviceType,
}),
method: 'POST',
}));
if (response.status !== 200) {
const error = await this.handleError(response, false);
return Promise.reject(error);
}
}
2018-01-09 22:19:55 +01:00
// Attachments APIs
async postCipherAttachment(id: string, data: FormData): Promise<CipherResponse> {
const authHeader = await this.handleTokenState();
2018-06-14 04:09:47 +02:00
const response = await fetch(new Request(this.apiBaseUrl + '/ciphers/' + id + '/attachment', {
2018-01-09 22:19:55 +01:00
body: data,
cache: 'no-cache',
2018-06-05 21:45:19 +02:00
credentials: this.getCredentials(),
2018-01-09 22:19:55 +01:00
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);
2018-06-12 17:45:02 +02:00
}
}
2018-06-12 19:07:06 +02:00
async deleteCipherAttachment(id: string, attachmentId: string): Promise<any> {
const authHeader = await this.handleTokenState();
2018-06-14 04:09:47 +02:00
const response = await fetch(new Request(this.apiBaseUrl + '/ciphers/' + id + '/attachment/' + attachmentId, {
2018-06-12 19:07:06 +02:00
cache: 'no-cache',
credentials: this.getCredentials(),
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);
}
}
async postShareCipherAttachment(id: string, attachmentId: string, data: FormData,
2018-06-12 17:45:02 +02:00
organizationId: string): Promise<any> {
const authHeader = await this.handleTokenState();
2018-06-14 04:09:47 +02:00
const response = await fetch(new Request(this.apiBaseUrl + '/ciphers/' + id + '/attachment/' +
2018-06-12 17:45:02 +02:00
attachmentId + '/share?organizationId=' + organizationId, {
body: data,
cache: 'no-cache',
credentials: this.getCredentials(),
headers: new Headers({
'Accept': 'application/json',
'Authorization': authHeader,
'Device-Type': this.deviceType,
}),
method: 'POST',
}));
if (response.status !== 200) {
const error = await this.handleError(response, false);
return Promise.reject(error);
2018-01-09 22:19:55 +01:00
}
}
// Sync APIs
async getSync(): Promise<SyncResponse> {
const authHeader = await this.handleTokenState();
2018-06-14 04:09:47 +02:00
const response = await fetch(new Request(this.apiBaseUrl + '/sync', {
2018-01-09 22:19:55 +01:00
cache: 'no-cache',
2018-06-05 21:45:19 +02:00
credentials: this.getCredentials(),
2018-01-09 22:19:55 +01:00
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);
}
}
async postImportDirectory(organizationId: string, request: ImportDirectoryRequest): Promise<any> {
const authHeader = await this.handleTokenState();
2018-06-14 04:09:47 +02:00
const response = await fetch(new Request(this.apiBaseUrl + '/organizations/' + organizationId + '/import', {
body: JSON.stringify(request),
cache: 'no-cache',
2018-06-05 21:45:19 +02:00
credentials: this.getCredentials(),
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 error = await this.handleError(response, false);
return Promise.reject(error);
}
}
2018-01-09 22:19:55 +01:00
// Helpers
private async handleError(response: Response, tokenError: boolean): Promise<ErrorResponse> {
if ((tokenError && response.status === 400) || response.status === 401 || response.status === 403) {
2018-05-16 05:40:15 +02:00
await this.logoutCallback(true);
2018-01-09 22:19:55 +01:00
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> {
2018-05-15 05:56:27 +02:00
let accessToken = await this.tokenService.getToken();
2018-01-09 22:19:55 +01:00
if (this.tokenService.tokenNeedsRefresh()) {
const tokenResponse = await this.doRefreshToken();
accessToken = tokenResponse.accessToken;
}
return 'Bearer ' + accessToken;
}
private async doRefreshToken(): Promise<IdentityTokenResponse> {
const refreshToken = await this.tokenService.getRefreshToken();
if (refreshToken == null || refreshToken === '') {
throw new Error();
}
2018-03-29 03:54:21 +02:00
const decodedToken = this.tokenService.decodeToken();
2018-01-09 22:19:55 +01:00
const response = await fetch(new Request(this.identityBaseUrl + '/connect/token', {
body: this.qsStringify({
grant_type: 'refresh_token',
2018-03-29 03:54:21 +02:00
client_id: decodedToken.client_id,
2018-01-09 22:19:55 +01:00
refresh_token: refreshToken,
}),
cache: 'no-cache',
2018-06-05 21:45:19 +02:00
credentials: this.getCredentials(),
2018-01-09 22:19:55 +01:00
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('&');
}
2018-06-05 21:45:19 +02:00
private getCredentials(): RequestCredentials {
if (!this.isWebClient || this.usingBaseUrl) {
return 'include';
}
return undefined;
}
2018-01-09 22:19:55 +01:00
}