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==",
"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": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@types/marked/-/marked-0.3.0.tgz",
@ -297,6 +302,11 @@
"integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=",
"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": {
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/marked/-/marked-0.3.9.tgz",

View File

@ -33,7 +33,9 @@
"typescript": "^2.7.1"
},
"dependencies": {
"lunr": "2.1.6",
"node-forge": "0.7.1",
"@types/lunr": "2.1.5",
"@types/node-forge": "0.7.1",
"@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 {
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';
const PwnedPasswordsApi = 'https://api.pwnedpasswords.com/range/';
export class AuditService {
export class AuditService implements AuditServiceAbstraction {
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 + '*';
}
}