Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions css/popup.css
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ body {
display: block;
}

#codes.timeout .code:not(.hotp) {
#codes:not(.edit) .code.timeout:not(.hotp) {
animation: twinkling 1s infinite ease-in-out;
}

Expand Down Expand Up @@ -588,12 +588,16 @@ body {
stroke: gray;
stroke-width: 8px;
stroke-dasharray: 25.12;
animation: 30s linear infinite timer;
animation-name: timer;
animation-iteration-count: infinite;
animation-timing-function: linear;
}

#codes.edit .sector,
#codes.edit .counter {
display: none;
position: absolute;
left: -1000px;
opacity: 0;
}

#menu {
Expand Down
10 changes: 10 additions & 0 deletions src/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ async function getTotp(text: string, passphrase: string) {
let account = '';
let secret = '';
let issuer = '';
let period: number|undefined = undefined;

try {
label = decodeURIComponent(label);
Expand All @@ -106,6 +107,12 @@ async function getTotp(text: string, passphrase: string) {
} else if (parameter[0].toLowerCase() === 'counter') {
let counter = Number(parameter[1]);
counter = (isNaN(counter) || counter < 0) ? 0 : counter;
} else if (parameter[0].toLowerCase() === 'period') {
period = Number(parameter[1]);
period = (isNaN(period) || period < 0 || period > 60 ||
60 % period !== 0) ?
undefined :
period;
}
});

Expand Down Expand Up @@ -136,6 +143,9 @@ async function getTotp(text: string, passphrase: string) {
index: 0,
counter: 0
};
if (period) {
entryData[hash].period = period;
}
await EntryStorage.import(encryption, entryData);
chrome.tabs.sendMessage(id, {action: 'added', account});
}
Expand Down
1 change: 0 additions & 1 deletion src/models/encryption.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ class Encryption {
!/^[0-9a-f]+$/i.test(decryptedSecret) &&
!/^blz\-/.test(decryptedSecret) && !/^bliz\-/.test(decryptedSecret) &&
!/^stm\-/.test(decryptedSecret)) {
console.log(decryptedSecret);
return 'Encrypted';
}

Expand Down
2 changes: 2 additions & 0 deletions src/models/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ interface OTP {
hash: string;
counter: number;
code: string;
period: number;
create(encryption: Encryption): Promise<void>;
update(encryption: Encryption): Promise<void>;
next(encryption: Encryption): Promise<void>;
Expand All @@ -35,6 +36,7 @@ interface OTPStorage {
secret: string;
type: string;
counter: number;
period?: number;
}

/* tslint:disable-next-line:interface-name */
Expand Down
5 changes: 3 additions & 2 deletions src/models/key-utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ class KeyUtilities {
return output;
}

static generate(type: OTPType, secret: string, counter: number) {
static generate(
type: OTPType, secret: string, counter: number, period: number) {
secret = secret.replace(/\s/g, '');
let len = 6;
let b26 = false;
Expand Down Expand Up @@ -128,7 +129,7 @@ class KeyUtilities {
if (localStorage.offset) {
epoch = epoch + Number(localStorage.offset);
}
counter = Math.floor(epoch / 30);
counter = Math.floor(epoch / period);
}

const time = this.leftpad(this.dec2hex(counter), 16, '0');
Expand Down
11 changes: 9 additions & 2 deletions src/models/otp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ class OTPEntry implements OTP {
account: string;
hash: string;
counter: number;
period: number;
code = '&bull;&bull;&bull;&bull;&bull;&bull;';

constructor(
type: OTPType, issuer: string, secret: string, account: string,
index: number, counter: number, hash?: string) {
index: number, counter: number, period?: number, hash?: string) {
this.type = type;
this.index = index;
this.issuer = issuer;
Expand All @@ -26,6 +27,11 @@ class OTPEntry implements OTP {
hash :
CryptoJS.MD5(secret).toString();
this.counter = counter;
if (this.type === OTPType.totp && period) {
this.period = period;
} else {
this.period = 30;
}
if (this.type !== OTPType.hotp && this.type !== OTPType.hhex) {
this.generate();
}
Expand Down Expand Up @@ -61,7 +67,8 @@ class OTPEntry implements OTP {
this.code = 'Encrypted';
} else {
try {
this.code = KeyUtilities.generate(this.type, this.secret, this.counter);
this.code = KeyUtilities.generate(
this.type, this.secret, this.counter, this.period);
} catch (error) {
this.code = 'Invalid';
if (parent) {
Expand Down
13 changes: 12 additions & 1 deletion src/models/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ class EntryStorage {
data[hash].issuer = data[hash].issuer || '';
data[hash].type = data[hash].type || OTPType[OTPType.totp];
data[hash].counter = data[hash].counter || 0;
const period = data[hash].period;
if (data[hash].type !== OTPType[OTPType.totp] ||
period && (isNaN(period) || period <= 0)) {
delete data[hash].period;
}

if (/^(blz\-|bliz\-)/.test(data[hash].secret)) {
const secretMatches =
Expand Down Expand Up @@ -306,6 +311,12 @@ class EntryStorage {
needMigrate = true;
}

let period = 30;
if (entryData.type === OTPType[OTPType.totp] &&
entryData.period && entryData.period > 0) {
period = entryData.period;
}

entryData.secret = entryData.encrypted ?
encryption.getDecryptedSecret(entryData.secret, hash) :
entryData.secret;
Expand Down Expand Up @@ -354,7 +365,7 @@ class EntryStorage {
const entry = new OTPEntry(
type, entryData.issuer, entryData.secret,
entryData.account, entryData.index, entryData.counter,
entryData.hash);
period, entryData.hash);
data.push(entry);

// <del>we need correct the hash</del>
Expand Down
37 changes: 23 additions & 14 deletions src/ui/entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ async function updateCode(app: any) {
let second = new Date().getSeconds();
if (localStorage.offset) {
// prevent second from negative
second += Number(localStorage.offset) + 30;
second += Number(localStorage.offset) + 60;
}
second = second % 30;

second = second % 60;
app.second = second;

// only when sector is not started (timer is not initialized),
// passphrase box should not be shown (no passphrase set) or
Expand All @@ -30,18 +32,24 @@ async function updateCode(app: any) {
app.sectorOffset = -second;
}

if (second > 25) {
app.class.timeout = true;
} else {
app.class.timeout = false;
}
if (second < 1) {
const entries = app.entries as OTP[];
for (let i = 0; i < entries.length; i++) {
if (entries[i].type !== OTPType.hotp &&
entries[i].type !== OTPType.hhex) {
entries[i].generate();
}
// if (second > 25) {
// app.class.timeout = true;
// } else {
// app.class.timeout = false;
// }
// if (second < 1) {
// const entries = app.entries as OTP[];
// for (let i = 0; i < entries.length; i++) {
// if (entries[i].type !== OTPType.hotp &&
// entries[i].type !== OTPType.hhex) {
// entries[i].generate();
// }
// }
// }
const entries = app.entries as OTP[];
for (let i = 0; i < entries.length; i++) {
if (entries[i].type !== OTPType.hotp && entries[i].type !== OTPType.hhex) {
entries[i].generate();
}
}
}
Expand Down Expand Up @@ -226,6 +234,7 @@ async function entry(_ui: UI) {
sector: '',
sectorStart: false,
sectorOffset: 0,
second: 0,
notification: '',
notificationTimeout: 0,
filter: true,
Expand Down
2 changes: 1 addition & 1 deletion src/ui/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class UI {
this.instance.updateCode();
setInterval(async () => {
await this.instance.updateCode();
}, 500);
}, 1000);
}, 0);

return this.instance;
Expand Down
4 changes: 2 additions & 2 deletions view/popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,15 @@
<div class="deleteAction" v-on:click="removeEntry(entry)"><i class="fa fa-minus-circle"></i></div>
<div class="sector" v-if="entry.type !== OTPType.hotp && entry.type !== OTPType.hhex" v-show="sectorStart">
<svg viewBox="0 0 16 16">
<circle cx="8" cy="8" r="4" v-bind:style="{animationDelay: sectorOffset + 's'}"/>
<circle cx="8" cy="8" r="4" v-bind:style="{animationDuration: entry.period + 's', animationDelay: (sectorOffset % entry.period) + 's'}"/>
</svg>
</div>
<div v-bind:class="{'counter': true, 'disabled': class.hotpDiabled}" v-if="entry.type === OTPType.hotp || entry.type === OTPType.hhex" v-on:click="nextCode(entry)"><i class="fa fa-repeat"></i></div>
<div class="issuer">{{ entry.issuer.split('::')[0] }}</div>
<div class="issuerEdit">
<input class="issuerEditBox" placeholder="{{ i18n.issuer }}" type="text" v-model="entry.issuer" v-on:change="entry.update(encryption)">
</div>
<div v-bind:class="{'code': true, 'hotp': entry.type === OTPType.hotp || entry.type === OTPType.hhex, 'no-copy': noCopy(entry.code)}" v-on:click="copyCode(entry)" v-html="class.edit ? showBulls(entry.code) : entry.code"></div>
<div v-bind:class="{'code': true, 'hotp': entry.type === OTPType.hotp || entry.type === OTPType.hhex, 'no-copy': noCopy(entry.code), 'timeout': entry.period - second % entry.period < 5 }" v-on:click="copyCode(entry)" v-html="class.edit ? showBulls(entry.code) : entry.code"></div>
<div class="account">{{ entry.account }}</div>
<div class="accountEdit">
<input class="accountEditBox" placeholder="{{ i18n.accountName }}" type="text" v-model="entry.account" v-on:change="entry.update(encryption)">
Expand Down