1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-11-06 09:20:43 +01:00

search service with lunr implementation

This commit is contained in:
Kyle Spearrin 2018-02-28 15:15:10 -05:00
parent e3b3e444db
commit 6aef18ee7f
6 changed files with 88 additions and 1 deletions

10
package-lock.json generated
View File

@ -31,6 +31,11 @@
"integrity": "sha512-BZknw3E/z3JmCLqQVANcR17okqVTPZdlxvcIz0fJiJVLUCbSH1hK3zs9r634PVSmrzAxN+n/fxlVRiYoArdOIQ==", "integrity": "sha512-BZknw3E/z3JmCLqQVANcR17okqVTPZdlxvcIz0fJiJVLUCbSH1hK3zs9r634PVSmrzAxN+n/fxlVRiYoArdOIQ==",
"dev": true "dev": true
}, },
"@types/lunr": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@types/lunr/-/lunr-2.1.5.tgz",
"integrity": "sha512-esk3CG25hRtHsVHm+LOjiSFYdw8be3uIY653WUwR43Bro914HSimPgPpqgajkhTJ0awK3RQfaIxP7zvbtCpcyg=="
},
"@types/marked": { "@types/marked": {
"version": "0.3.0", "version": "0.3.0",
"resolved": "https://registry.npmjs.org/@types/marked/-/marked-0.3.0.tgz", "resolved": "https://registry.npmjs.org/@types/marked/-/marked-0.3.0.tgz",
@ -297,6 +302,11 @@
"integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=",
"dev": true "dev": true
}, },
"lunr": {
"version": "2.1.6",
"resolved": "https://registry.npmjs.org/lunr/-/lunr-2.1.6.tgz",
"integrity": "sha512-ydJpB8CX8cZ/VE+KMaYaFcZ6+o2LruM6NG76VXdflYTgluvVemz1lW4anE+pyBbLvxJHZdvD1Jy/fOqdzAEJog=="
},
"marked": { "marked": {
"version": "0.3.9", "version": "0.3.9",
"resolved": "https://registry.npmjs.org/marked/-/marked-0.3.9.tgz", "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.9.tgz",

View File

@ -33,7 +33,9 @@
"typescript": "^2.7.1" "typescript": "^2.7.1"
}, },
"dependencies": { "dependencies": {
"lunr": "2.1.6",
"node-forge": "0.7.1", "node-forge": "0.7.1",
"@types/lunr": "2.1.5",
"@types/node-forge": "0.7.1", "@types/node-forge": "0.7.1",
"@types/webcrypto": "0.0.28" "@types/webcrypto": "0.0.28"
} }

View File

@ -0,0 +1,6 @@
import { CipherView } from '../models/view/cipherView';
export abstract class SearchService {
indexCiphers: () => Promise<void>;
searchCiphers: (query: string) => Promise<CipherView[]>;
}

View File

@ -65,4 +65,12 @@ export class CipherView implements View {
get hasFields(): boolean { get hasFields(): boolean {
return this.fields && this.fields.length > 0; return this.fields && this.fields.length > 0;
} }
get login_username(): string {
return this.login != null ? this.login.username : null;
}
get login_uri(): string {
return this.login != null ? this.login.uri : null;
}
} }

View File

@ -1,8 +1,9 @@
import { AuditService as AuditServiceAbstraction } from '../abstractions/audit.service';
import { CryptoService } from '../abstractions/crypto.service'; import { CryptoService } from '../abstractions/crypto.service';
const PwnedPasswordsApi = 'https://api.pwnedpasswords.com/range/'; const PwnedPasswordsApi = 'https://api.pwnedpasswords.com/range/';
export class AuditService { export class AuditService implements AuditServiceAbstraction {
constructor(private cryptoService: CryptoService) { constructor(private cryptoService: CryptoService) {
} }

View File

@ -0,0 +1,60 @@
import * as lunr from 'lunr';
import { CipherView } from '../models/view/cipherView';
import { CipherService } from '../abstractions/cipher.service';
import { SearchService as SearchServiceAbstraction } from '../abstractions/search.service';
export class SearchService implements SearchServiceAbstraction {
private index: lunr.Index;
constructor(private cipherService: CipherService) {
}
async indexCiphers(): Promise<void> {
const builder = new lunr.Builder();
builder.ref('id');
builder.field('name');
builder.field('subTitle');
builder.field('notes');
builder.field('login_username');
builder.field('login_uri');
const ciphers = await this.cipherService.getAllDecrypted();
ciphers.forEach((c) => {
builder.add(c);
});
this.index = builder.build();
}
async searchCiphers(query: string): Promise<CipherView[]> {
const results: CipherView[] = [];
if (this.index == null) {
return results;
}
const ciphers = await this.cipherService.getAllDecrypted();
const ciphersMap = new Map<string, CipherView>();
ciphers.forEach((c) => {
ciphersMap.set(c.id, c);
});
query = this.transformQuery(query);
const searchResults = this.index.search(query);
searchResults.forEach((r) => {
if (ciphersMap.has(r.ref)) {
results.push(ciphersMap.get(r.ref));
}
});
return results;
}
private transformQuery(query: string) {
if (query.indexOf('>') === 0) {
return query.substr(1).trimLeft();
}
return '*' + query + '*';
}
}