convert totp service to jslib

This commit is contained in:
Kyle Spearrin 2018-01-09 17:45:17 -05:00
parent cfbd67060a
commit 79aca025d0
3 changed files with 4 additions and 120 deletions

View File

@ -5,6 +5,7 @@ import {
AppIdService, AppIdService,
CryptoService, CryptoService,
TokenService, TokenService,
TotpService,
UserService, UserService,
UtilsService, UtilsService,
} from 'jslib/services'; } from 'jslib/services';
@ -17,6 +18,7 @@ import {
PlatformUtilsService as PlatformUtilsServiceAbstraction, PlatformUtilsService as PlatformUtilsServiceAbstraction,
StorageService as StorageServiceAbstraction, StorageService as StorageServiceAbstraction,
TokenService as TokenServiceAbstraction, TokenService as TokenServiceAbstraction,
TotpService as TotpServiceAbstraction,
UserService as UserServiceAbstraction, UserService as UserServiceAbstraction,
UtilsService as UtilsServiceAbstraction, UtilsService as UtilsServiceAbstraction,
} from 'jslib/abstractions'; } from 'jslib/abstractions';
@ -46,7 +48,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 TotpService from '../services/totp.service';
export default class MainBackground { export default class MainBackground {
messagingService: MessagingServiceAbstraction; messagingService: MessagingServiceAbstraction;
@ -68,7 +69,7 @@ export default class MainBackground {
lockService: LockService; lockService: LockService;
syncService: SyncService; syncService: SyncService;
passwordGenerationService: PasswordGenerationService; passwordGenerationService: PasswordGenerationService;
totpService: TotpService; totpService: TotpServiceAbstraction;
autofillService: AutofillService; autofillService: AutofillService;
containerService: ContainerService; containerService: ContainerService;

View File

@ -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 TotpService from './totp.service';
import { UtilsService } from 'jslib/services'; import { UtilsService } from 'jslib/services';
import { import {
PlatformUtilsService, PlatformUtilsService,
TokenService, TokenService,
TotpService,
UtilsService as UtilsServiceAbstraction, UtilsService as UtilsServiceAbstraction,
} from 'jslib/abstractions'; } from 'jslib/abstractions';

View File

@ -1,117 +0,0 @@
import ConstantsService from './constants.service';
import { StorageService } from 'jslib/abstractions';
const b32Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
const TotpAlgorithm = {
name: 'HMAC',
hash: { name: 'SHA-1' },
};
export default class TotpService {
constructor(private storageService: StorageService) {
}
async getCode(keyb32: string): Promise<string> {
const epoch = Math.round(new Date().getTime() / 1000.0);
const timeHex = this.leftpad(this.dec2hex(Math.floor(epoch / 30)), 16, '0');
const timeBytes = this.hex2bytes(timeHex);
const keyBytes = this.b32tobytes(keyb32);
if (!keyBytes.length || !timeBytes.length) {
return null;
}
const hashHex = await this.sign(keyBytes, timeBytes);
if (!hashHex) {
return null;
}
const offset = this.hex2dec(hashHex.substring(hashHex.length - 1));
// tslint:disable-next-line
let otp = (this.hex2dec(hashHex.substr(offset * 2, 8)) & this.hex2dec('7fffffff')) + '';
otp = (otp).substr(otp.length - 6, 6);
return otp;
}
async isAutoCopyEnabled(): Promise<boolean> {
return !(await this.storageService.get<boolean>(ConstantsService.disableAutoTotpCopyKey));
}
// Helpers
private leftpad(s: string, l: number, p: string): string {
if (l + 1 >= s.length) {
s = Array(l + 1 - s.length).join(p) + s;
}
return s;
}
private dec2hex(d: number): string {
return (d < 15.5 ? '0' : '') + Math.round(d).toString(16);
}
private hex2dec(s: string): number {
return parseInt(s, 16);
}
private hex2bytes(s: string): Uint8Array {
const bytes = new Uint8Array(s.length / 2);
for (let i = 0; i < s.length; i += 2) {
bytes[i / 2] = parseInt(s.substr(i, 2), 16);
}
return bytes;
}
private buff2hex(buff: ArrayBuffer): string {
const bytes = new Uint8Array(buff);
const hex: string[] = [];
bytes.forEach((b) => {
// tslint:disable-next-line
hex.push((b >>> 4).toString(16));
// tslint:disable-next-line
hex.push((b & 0xF).toString(16));
});
return hex.join('');
}
private b32tohex(s: string): string {
s = s.toUpperCase();
let cleanedInput = '';
for (let i = 0; i < s.length; i++) {
if (b32Chars.indexOf(s[i]) < 0) {
continue;
}
cleanedInput += s[i];
}
s = cleanedInput;
let bits = '';
let hex = '';
for (let i = 0; i < s.length; i++) {
const byteIndex = b32Chars.indexOf(s.charAt(i));
if (byteIndex < 0) {
continue;
}
bits += this.leftpad(byteIndex.toString(2), 5, '0');
}
for (let i = 0; i + 4 <= bits.length; i += 4) {
const chunk = bits.substr(i, 4);
hex = hex + parseInt(chunk, 2).toString(16);
}
return hex;
}
private b32tobytes(s: string): Uint8Array {
return this.hex2bytes(this.b32tohex(s));
}
private async sign(keyBytes: Uint8Array, timeBytes: Uint8Array) {
const key = await window.crypto.subtle.importKey('raw', keyBytes, TotpAlgorithm, false, ['sign']);
const signature = await window.crypto.subtle.sign(TotpAlgorithm, key, timeBytes);
return this.buff2hex(signature);
}
}