Finilization v1.1.0.0

This commit is contained in:
Sergej Schwabauer 2023-04-13 19:29:30 +02:00
parent 2b3da349b0
commit e10ba53c1a
14 changed files with 260 additions and 87 deletions

View File

@ -3,7 +3,7 @@
"solution": { "solution": {
"name": "SPFx app dev Simple Password Vault", "name": "SPFx app dev Simple Password Vault",
"id": "d091b369-f63d-459c-846e-5a4323e31745", "id": "d091b369-f63d-459c-846e-5a4323e31745",
"version": "1.0.0.0", "version": "1.1.0.0",
"includeClientSideAssets": true, "includeClientSideAssets": true,
"skipFeatureDeployment": true, "skipFeatureDeployment": true,
"isDomainIsolated": false, "isDomainIsolated": false,

View File

@ -1,6 +1,6 @@
{ {
"name": "sp-fx-app-dev-simple-password-vault", "name": "sp-fx-app-dev-simple-password-vault",
"version": "1.0.0", "version": "1.1.0",
"private": true, "private": true,
"main": "lib/index.js", "main": "lib/index.js",
"engines": { "engines": {

View File

@ -1,6 +1,3 @@
export interface IVaultData { export interface IVaultData {
masterPW: string; masterPW: string;
// username: string;
// password: string;
// note: string;
} }

View File

@ -1,7 +1,6 @@
import * as CryptoJS from 'crypto-js'; import * as CryptoJS from 'crypto-js';
import { isNullOrEmpty, toBoolean } from '@spfxappdev/utility'; import { isNullOrEmpty, toBoolean } from '@spfxappdev/utility';
import { SessionStorage } from '@spfxappdev/storage'; import { SessionStorage } from '@spfxappdev/storage';
import { IVaultData } from '@src/models/IVaultData';
import { ModuleType } from '@src/models'; import { ModuleType } from '@src/models';
@ -71,7 +70,7 @@ export class PasswordVaultService implements IPasswordVaultService {
this.cache = new SessionStorage(cacheSettings); this.cache = new SessionStorage(cacheSettings);
this.isVaultOpen = toBoolean(this.cache.get(this.encryptedInstanceId)); this.isVaultOpen = toBoolean(this.cache.get(this.encryptedInstanceId));
let pwFromCache = this.cache.get(this.encryptedMasterPWInstanceId); const pwFromCache = this.cache.get(this.encryptedMasterPWInstanceId);
this.encryptedMasterPw = isNullOrEmpty(pwFromCache) ? "" : pwFromCache; this.encryptedMasterPw = isNullOrEmpty(pwFromCache) ? "" : pwFromCache;
if(!isNullOrEmpty(this.encryptedMasterPw)) { if(!isNullOrEmpty(this.encryptedMasterPw)) {
@ -103,7 +102,7 @@ export class PasswordVaultService implements IPasswordVaultService {
public open(masterPW: string, encryptedMasterPW: string): boolean { public open(masterPW: string, encryptedMasterPW: string): boolean {
const masterPWEncrypted = CryptoJS.HmacSHA256(masterPW, this.masterSecretKey); const masterPWEncrypted = CryptoJS.HmacSHA256(masterPW, this.masterSecretKey);
if(masterPWEncrypted.toString() == encryptedMasterPW) { if(masterPWEncrypted.toString() === encryptedMasterPW) {
this.isVaultOpen = true; this.isVaultOpen = true;
this.cache.set(this.encryptedInstanceId, true); this.cache.set(this.encryptedInstanceId, true);
this.encryptedMasterPw = this.encrypt(masterPW, this.masterSecretKey); this.encryptedMasterPw = this.encrypt(masterPW, this.masterSecretKey);
@ -115,7 +114,6 @@ export class PasswordVaultService implements IPasswordVaultService {
return false; return false;
} }
public isOpen(): boolean { public isOpen(): boolean {
return this.isVaultOpen; return this.isVaultOpen;
} }

View File

@ -22,9 +22,18 @@
"officeFabricIconFontName": "ProtectRestrict", "officeFabricIconFontName": "ProtectRestrict",
"properties": { "properties": {
"masterPW": "", "masterPW": "",
"username": "", "modules": [
"password": "", {
"note": "" "id": "718def44-3e0c-48bf-8843-ccabefece27e",
"data": "",
"type": "UserField"
},
{
"id": "65025036-e345-43f7-9561-6d3026294b2e",
"data": "",
"type": "PasswordField"
},
]
} }
}] }]
} }

View File

@ -39,15 +39,15 @@ export default class PasswordVaultWebPart extends SPFxAppDevClientSideWebPart<IP
Title: this.properties.Title, Title: this.properties.Title,
passwordVaultService: this.passwordVaultService, passwordVaultService: this.passwordVaultService,
masterPW: this.properties.masterPW, masterPW: this.properties.masterPW,
// username: this.properties.username,
// password: this.properties.password,
// note: this.properties.note,
modules: this.properties.modules||[], modules: this.properties.modules||[],
onTitleChanged: (title: string): void => { onTitleChanged: (title: string): void => {
this.onTitleChanged(title); this.onTitleChanged(title);
}, },
onVaultDataChanged: (encryptedMasterPw: string, modules: IModule[]): void => { onVaultDataChanged: (encryptedMasterPw: string, modules: IModule[]): void => {
this.onVaultDataChanged(encryptedMasterPw, modules); this.onVaultDataChanged(encryptedMasterPw, modules);
},
onVaultPasswordChanged: (encryptedMasterPw: string): void => {
this.onMasterPasswordChanged(encryptedMasterPw);
} }
} }
); );
@ -66,7 +66,7 @@ export default class PasswordVaultWebPart extends SPFxAppDevClientSideWebPart<IP
}); });
} }
if (!this.helper.functions.isNullOrEmpty(oldProps.username)) { if (!this.helper.functions.isNullOrEmpty(oldProps.password)) {
this.properties.modules.push({ this.properties.modules.push({
id: Guid.newGuid().toString(), id: Guid.newGuid().toString(),
type: ModuleType.PasswordField, type: ModuleType.PasswordField,
@ -81,6 +81,23 @@ export default class PasswordVaultWebPart extends SPFxAppDevClientSideWebPart<IP
data: oldProps.note data: oldProps.note
}); });
} }
this.removePropertiesFromOldVersion();
}
private removePropertiesFromOldVersion(): void {
const oldProps: any = this.properties as any;
if (this.helper.functions.isset(oldProps.username)) {
delete oldProps.username;
}
if (this.helper.functions.isset(oldProps.password)) {
delete oldProps.password;
}
if (this.helper.functions.isset(oldProps.note)) {
delete oldProps.note;
}
} }
public getLogCategory(): string { public getLogCategory(): string {
@ -94,9 +111,11 @@ export default class PasswordVaultWebPart extends SPFxAppDevClientSideWebPart<IP
public onVaultDataChanged(encryptedMasterPW: string, modules: IModule[]): void { public onVaultDataChanged(encryptedMasterPW: string, modules: IModule[]): void {
this.properties.masterPW = encryptedMasterPW; this.properties.masterPW = encryptedMasterPW;
this.properties.modules = modules; this.properties.modules = modules;
// this.properties.note = vaultData.note; this.removePropertiesFromOldVersion();
// this.properties.password = vaultData.password; }
// this.properties.username = vaultData.username;
private onMasterPasswordChanged(encryptedMasterPW: string): void {
this.properties.masterPW = encryptedMasterPW;
} }
protected onDispose(): void { protected onDispose(): void {

View File

@ -1,5 +1,4 @@
import * as React from 'react'; import * as React from 'react';
import styles from './PasswordVault.module.scss';
import * as strings from 'PasswordVaultWebPartStrings'; import * as strings from 'PasswordVaultWebPartStrings';
import { Label } from 'office-ui-fabric-react'; import { Label } from 'office-ui-fabric-react';
import { RichText } from "@pnp/spfx-controls-react/lib/RichText"; import { RichText } from "@pnp/spfx-controls-react/lib/RichText";

View File

@ -1,6 +1,5 @@
import * as React from 'react'; import * as React from 'react';
import styles from './PasswordVault.module.scss'; import { Callout, Icon, DirectionalHint, TextField, ITextField } from 'office-ui-fabric-react';
import { ActionButton, Callout, Icon, TooltipHost, DirectionalHint, TextField, ITextField } from 'office-ui-fabric-react';
import * as strings from 'PasswordVaultWebPartStrings'; import * as strings from 'PasswordVaultWebPartStrings';
import { getDeepOrDefault, issetDeep, isset } from '@spfxappdev/utility'; import { getDeepOrDefault, issetDeep, isset } from '@spfxappdev/utility';
@ -30,8 +29,6 @@ export default class PasswordField extends React.Component<IPasswordFieldProps,
} }
return this.renderEditMode(); return this.renderEditMode();
} }
public renderDisplayMode(): JSX.Element { public renderDisplayMode(): JSX.Element {

View File

@ -34,6 +34,7 @@
&::before { &::before {
border-top-style: solid; border-top-style: solid;
border-top-width: 2px; border-top-width: 2px;
border-top-color: $ms-color-neutralTertiary;
content: ""; content: "";
height: 0; height: 0;
position: absolute; position: absolute;
@ -49,6 +50,7 @@
border-radius: 50%; border-radius: 50%;
border-style: solid; border-style: solid;
border-width: 2px; border-width: 2px;
border-color: $ms-color-neutralTertiary;
box-sizing: border-box; box-sizing: border-box;
height: 24px; height: 24px;
line-height: 12px; line-height: 12px;
@ -57,7 +59,7 @@
position: relative; position: relative;
transition: opacity .3s ease-in-out; transition: opacity .3s ease-in-out;
width: 24px; width: 24px;
background-color: #000; background-color: $ms-color-neutralTertiary;
display: block; display: block;
@ -104,13 +106,19 @@
padding: 10px; padding: 10px;
} }
} }
:global {
.ms-CommandBar {
padding: 0 0 10px;
}
}
} }
:global { :global {
.ql-editor .ql-editor
{ {
padding: 0px !important; padding: 8px 0 0 !important;
} }
.ql-editor[contenteditable='true'] { .ql-editor[contenteditable='true'] {

View File

@ -3,7 +3,7 @@ import styles from './PasswordVault.module.scss';
import { SPFxAppDevWebPartComponent, ISPFxAppDevWebPartComponentProps } from '@spfxappdev/framework'; import { SPFxAppDevWebPartComponent, ISPFxAppDevWebPartComponentProps } from '@spfxappdev/framework';
import PasswordVaultWebPart from '../PasswordVaultWebPart'; import PasswordVaultWebPart from '../PasswordVaultWebPart';
import { IPasswordVaultService } from '@src/services/PasswordVaultService'; import { IPasswordVaultService } from '@src/services/PasswordVaultService';
import { DefaultButton, IconButton, MessageBar, MessageBarType, PrimaryButton, TextField } from 'office-ui-fabric-react'; import { Dialog, DefaultButton, IconButton, MessageBar, MessageBarType, PrimaryButton, TextField, CommandBar, ICommandBarItemProps, DialogFooter, DialogType } from 'office-ui-fabric-react';
import { WebPartTitle } from "@pnp/spfx-controls-react/lib/WebPartTitle"; import { WebPartTitle } from "@pnp/spfx-controls-react/lib/WebPartTitle";
import * as strings from 'PasswordVaultWebPartStrings'; import * as strings from 'PasswordVaultWebPartStrings';
import AddNewModule from './AddNewModule'; import AddNewModule from './AddNewModule';
@ -13,12 +13,14 @@ import UserField from './UserField';
import PasswordField from './PasswordField'; import PasswordField from './PasswordField';
import NoteField from './NoteField'; import NoteField from './NoteField';
import { cloneDeep } from '@microsoft/sp-lodash-subset'; import { cloneDeep } from '@microsoft/sp-lodash-subset';
import '@spfxappdev/utility/lib/extensions/ArrayExtensions';
interface IPasswordVaultState { interface IPasswordVaultState {
isVaultOpen: boolean; isVaultOpen: boolean;
showWrongMasterInfo: boolean; showWrongMasterInfo: boolean;
isSaveButtonDisabled: boolean; isSaveButtonDisabled: boolean;
modules: IModule[]; modules: IModule[];
showChangePasswordDialog: boolean;
} }
export interface IPasswordVaultProps extends ISPFxAppDevWebPartComponentProps<PasswordVaultWebPart> { export interface IPasswordVaultProps extends ISPFxAppDevWebPartComponentProps<PasswordVaultWebPart> {
@ -26,10 +28,10 @@ export interface IPasswordVaultProps extends ISPFxAppDevWebPartComponentProps<Pa
masterPW?: string; masterPW?: string;
onTitleChanged?(value: string): void; onTitleChanged?(value: string): void;
onVaultDataChanged?(encryptedMaster: string, modules: IModule[]): void; onVaultDataChanged?(encryptedMaster: string, modules: IModule[]): void;
onVaultPasswordChanged?(encryptedMaster: string): void;
modules?: IModule[]; modules?: IModule[];
} }
//TODO:
// "Change Password" as command button, only if vault already have set a master password
export default class PasswordVault extends SPFxAppDevWebPartComponent<PasswordVaultWebPart, IPasswordVaultProps, IPasswordVaultState> { export default class PasswordVault extends SPFxAppDevWebPartComponent<PasswordVaultWebPart, IPasswordVaultProps, IPasswordVaultState> {
@ -43,7 +45,8 @@ export default class PasswordVault extends SPFxAppDevWebPartComponent<PasswordVa
isVaultOpen: this.isVaultOpen, isVaultOpen: this.isVaultOpen,
showWrongMasterInfo: false, showWrongMasterInfo: false,
isSaveButtonDisabled: this.helper.functions.isNullOrEmpty(this.props.masterPW), isSaveButtonDisabled: this.helper.functions.isNullOrEmpty(this.props.masterPW),
modules: cloneDeep(this.props.modules) modules: cloneDeep(this.props.modules),
showChangePasswordDialog: false
}; };
private get isVaultOpen(): boolean { private get isVaultOpen(): boolean {
@ -61,6 +64,8 @@ export default class PasswordVault extends SPFxAppDevWebPartComponent<PasswordVa
private enteredMasterPW: string = ""; private enteredMasterPW: string = "";
private repeatedEnteredMasterPW: string = "";
private encryptedModuleData: Record<string, string> = {}; private encryptedModuleData: Record<string, string> = {};
private decryptedModuleData: Record<string, string> = {}; private decryptedModuleData: Record<string, string> = {};
@ -152,26 +157,17 @@ export default class PasswordVault extends SPFxAppDevWebPartComponent<PasswordVa
{showForm && {showForm &&
<> <>
<MessageBar messageBarType={MessageBarType.warning}>
{strings.DontLoseMasterpasswordLabel} {this.renderCommandBarButtons()}
</MessageBar> {this.renderChangePasswordDialog()}
{this.isNewVault &&
<MessageBar messageBarType={MessageBarType.warning}>
{strings.DontLoseMasterpasswordLabel}
</MessageBar>
}
<div className='spfxappdev-grid'> <div className='spfxappdev-grid'>
<div className="spfxappdev-grid-row"> {this.isNewVault && this.renderMasterPasswordControls()}
<div className="spfxappdev-grid-col spfxappdev-sm12">
<TextField
label={this.isNewVault ? strings.SetMasterPasswordLabel : strings.ChangeMasterPasswordLabel}
type="password"
required={this.isNewVault}
canRevealPassword={true}
onChange={(ev: any, newValue: string) => {
this.enteredMasterPW = newValue;
this.setState({
isSaveButtonDisabled: this.isSaveButtonDisabled()
});
}}
/>
</div>
</div>
{this.state.modules.map((module: IModule, index: number): JSX.Element => { {this.state.modules.map((module: IModule, index: number): JSX.Element => {
return this.renderModuleEditMode(module, index); return this.renderModuleEditMode(module, index);
@ -187,31 +183,7 @@ export default class PasswordVault extends SPFxAppDevWebPartComponent<PasswordVa
<div className="spfxappdev-grid-row grid-footer"> <div className="spfxappdev-grid-row grid-footer">
<div className="spfxappdev-grid-col spfxappdev-sm12"> <div className="spfxappdev-grid-col spfxappdev-sm12">
<PrimaryButton disabled={this.state.isSaveButtonDisabled} onClick={() => { <PrimaryButton disabled={this.state.isSaveButtonDisabled} onClick={() => {
this.isNewVault = false; this.onSaveButtonClick();
let encryptedMaster = this.currentMasterPW;
if(!this.enteredMasterPW.IsEmpty()) {
encryptedMaster = this.props.passwordVaultService.setMasterPassword(this.enteredMasterPW);
this.currentMasterPW = encryptedMaster;
}
const encryptedModules: IModule[] = [];
this.state.modules.forEach((module: IModule) => {
const encryptedValue: string = this.props.passwordVaultService.encryptModuleData(module.type, this.decryptedModuleData[module.id]);
encryptedModules.push({
id: module.id,
data: encryptedValue,
type: module.type
});
});
this.props.onVaultDataChanged(encryptedMaster, encryptedModules);
this.setState({
modules: encryptedModules
});
}}> }}>
{strings.SaveLabel} {strings.SaveLabel}
</PrimaryButton> </PrimaryButton>
@ -274,19 +246,19 @@ export default class PasswordVault extends SPFxAppDevWebPartComponent<PasswordVa
<div className={styles["edit-container--content"]}> <div className={styles["edit-container--content"]}>
{module.type == ModuleType.UserField && {module.type === ModuleType.UserField &&
<UserField defaultValue={this.decryptedModuleData[module.id]} tabIndex={index} onChange={(newVal: string) => { <UserField defaultValue={this.decryptedModuleData[module.id]} tabIndex={index} onChange={(newVal: string) => {
this.decryptedModuleData[module.id] = newVal; this.decryptedModuleData[module.id] = newVal;
}} isDisplayMode={false} /> }} isDisplayMode={false} />
} }
{module.type == ModuleType.PasswordField && {module.type === ModuleType.PasswordField &&
<PasswordField defaultValue={this.decryptedModuleData[module.id]} tabIndex={index} onChange={(newVal: string) => { <PasswordField defaultValue={this.decryptedModuleData[module.id]} tabIndex={index} onChange={(newVal: string) => {
this.decryptedModuleData[module.id] = newVal; this.decryptedModuleData[module.id] = newVal;
}} isDisplayMode={false} /> }} isDisplayMode={false} />
} }
{module.type == ModuleType.NoteField && {module.type === ModuleType.NoteField &&
<NoteField defaultValue={this.decryptedModuleData[module.id]} onChange={(newVal: string) => { <NoteField defaultValue={this.decryptedModuleData[module.id]} onChange={(newVal: string) => {
this.decryptedModuleData[module.id] = newVal; this.decryptedModuleData[module.id] = newVal;
@ -307,15 +279,15 @@ export default class PasswordVault extends SPFxAppDevWebPartComponent<PasswordVa
<> <>
<div className="spfxappdev-grid-row" key={module.id}> <div className="spfxappdev-grid-row" key={module.id}>
<div className="spfxappdev-grid-col spfxappdev-sm12"> <div className="spfxappdev-grid-col spfxappdev-sm12">
{module.type == ModuleType.UserField && {module.type === ModuleType.UserField &&
<UserField defaultValue={this.decryptedModuleData[module.id]} isDisplayMode={true} tabIndex={index} /> <UserField defaultValue={this.decryptedModuleData[module.id]} isDisplayMode={true} tabIndex={index} />
} }
{module.type == ModuleType.PasswordField && {module.type === ModuleType.PasswordField &&
<PasswordField defaultValue={this.decryptedModuleData[module.id]} isDisplayMode={true} tabIndex={index} /> <PasswordField defaultValue={this.decryptedModuleData[module.id]} isDisplayMode={true} tabIndex={index} />
} }
{module.type == ModuleType.NoteField && {module.type === ModuleType.NoteField &&
<NoteField defaultValue={this.decryptedModuleData[module.id]} isDisplayMode={true} /> <NoteField defaultValue={this.decryptedModuleData[module.id]} isDisplayMode={true} />
} }
</div> </div>
@ -350,7 +322,7 @@ export default class PasswordVault extends SPFxAppDevWebPartComponent<PasswordVa
this.enteredMasterPW = newValue; this.enteredMasterPW = newValue;
}} }}
onKeyUp={(ev: React.KeyboardEvent<HTMLInputElement>) => { onKeyUp={(ev: React.KeyboardEvent<HTMLInputElement>) => {
if(ev.keyCode == 13) { if(ev.keyCode === 13) {
this.onOpenVault(); this.onOpenVault();
} }
}} }}
@ -375,9 +347,123 @@ export default class PasswordVault extends SPFxAppDevWebPartComponent<PasswordVa
</>); </>);
} }
private renderMasterPasswordControls(): JSX.Element {
return (
<div className="spfxappdev-grid-row">
<div className="spfxappdev-grid-col spfxappdev-sm12">
<TextField
label={this.isNewVault ? strings.SetMasterPasswordLabel : strings.ChangeMasterPasswordLabel}
type="password"
required={this.isNewVault}
canRevealPassword={true}
onChange={(ev: any, newValue: string) => {
this.enteredMasterPW = newValue;
this.setState({
isSaveButtonDisabled: this.isSaveButtonDisabled()
});
}}
/>
</div>
<div className="spfxappdev-grid-col spfxappdev-sm12">
<TextField
label={strings.RepeatMasterPasswordLabel}
type="password"
required={this.isNewVault}
canRevealPassword={true}
onChange={(ev: any, newValue: string) => {
this.repeatedEnteredMasterPW = newValue;
this.setState({
isSaveButtonDisabled: this.isSaveButtonDisabled()
});
}}
/>
</div>
</div>);
}
private renderChangePasswordDialog(): JSX.Element {
return (
<Dialog
hidden={!this.state.showChangePasswordDialog}
dialogContentProps={{
title: strings.ChangeMasterPasswordDialogTitle,
type: DialogType.normal,
}}
onDismiss={() => { this.toggleChangePasswordDialogVisibility(); }}
>
<MessageBar messageBarType={MessageBarType.warning}>
{strings.DontLoseMasterpasswordLabel}
</MessageBar>
{this.renderMasterPasswordControls()}
<DialogFooter>
<PrimaryButton
disabled={this.state.isSaveButtonDisabled}
onClick={() => { this.onChangePasswordClick(); }}
text={strings.SaveLabel} />
<DefaultButton onClick={() => { this.toggleChangePasswordDialogVisibility(); }} text={strings.CancelLabel} />
</DialogFooter>
</Dialog>
);
}
private renderCommandBarButtons(): JSX.Element {
const buttons: ICommandBarItemProps[] = [];
const saveButton: ICommandBarItemProps = {
key: 'saveSettings',
text: strings.SaveLabel,
disabled: this.isSaveButtonDisabled(),
iconProps: { iconName: 'Save' },
onClick: () => {
this.onSaveButtonClick();
}
}
buttons.push(saveButton);
if(!this.isNewVault) {
const changeMasterPwButton: ICommandBarItemProps = {
key: 'changeMasterPassword',
text: strings.ChangeMasterPasswordButtonText,
iconProps: { iconName: 'PasswordField' },
onClick: () => {
this.toggleChangePasswordDialogVisibility();
},
}
buttons.push(changeMasterPwButton);
}
if(!this.helper.functions.isNullOrEmpty(this.currentMasterPW)) {
const closeButton: ICommandBarItemProps = {
key: 'closeVault',
text: strings.CloseVaultLabel,
iconProps: { iconName: 'Lock' },
onClick: () => {
this.closeVault();
}
}
buttons.push(closeButton);
}
return (
<CommandBar
items={buttons}
/>
);
}
private isSaveButtonDisabled(): boolean { private isSaveButtonDisabled(): boolean {
if(this.isNewVault && this.helper.functions.isNullOrEmpty(this.enteredMasterPW)) { if((this.isNewVault || this.state.showChangePasswordDialog) && this.helper.functions.isNullOrEmpty(this.enteredMasterPW)) {
return true;
}
if(!this.enteredMasterPW.Equals(this.repeatedEnteredMasterPW, false)) {
return true; return true;
} }
@ -404,8 +490,6 @@ export default class PasswordVault extends SPFxAppDevWebPartComponent<PasswordVa
}); });
} }
console.log("SSC onOpen", this.decryptedModuleData);
this.setState({ this.setState({
isVaultOpen: isCorrectPW, isVaultOpen: isCorrectPW,
showWrongMasterInfo: !isCorrectPW showWrongMasterInfo: !isCorrectPW
@ -461,4 +545,55 @@ export default class PasswordVault extends SPFxAppDevWebPartComponent<PasswordVa
modules: this.state.modules modules: this.state.modules
}); });
} }
private onSaveButtonClick(): void {
this.isNewVault = false;
let encryptedMaster = this.currentMasterPW;
if(!this.enteredMasterPW.IsEmpty()) {
encryptedMaster = this.props.passwordVaultService.setMasterPassword(this.enteredMasterPW);
this.currentMasterPW = encryptedMaster;
}
const encryptedModules: IModule[] = [];
this.state.modules.forEach((module: IModule) => {
const encryptedValue: string = this.props.passwordVaultService.encryptModuleData(module.type, this.decryptedModuleData[module.id]);
encryptedModules.push({
id: module.id,
data: encryptedValue,
type: module.type
});
});
this.props.onVaultDataChanged(encryptedMaster, encryptedModules);
this.setState({
modules: encryptedModules
});
this.enteredMasterPW = '';
this.repeatedEnteredMasterPW = '';
}
private onChangePasswordClick(): void {
let encryptedMaster = this.currentMasterPW;
if(!this.enteredMasterPW.IsEmpty()) {
encryptedMaster = this.props.passwordVaultService.setMasterPassword(this.enteredMasterPW);
this.currentMasterPW = encryptedMaster;
this.props.onVaultPasswordChanged(encryptedMaster);
}
this.enteredMasterPW = '';
this.repeatedEnteredMasterPW = '';
this.toggleChangePasswordDialogVisibility();
}
private toggleChangePasswordDialogVisibility(): void {
this.setState({
showChangePasswordDialog: !this.state.showChangePasswordDialog,
isSaveButtonDisabled: !this.state.showChangePasswordDialog
});
}
} }

View File

@ -1,6 +1,5 @@
import * as React from 'react'; import * as React from 'react';
import styles from './PasswordVault.module.scss'; import { Callout, Icon, DirectionalHint, TextField, ITextField } from 'office-ui-fabric-react';
import { ActionButton, Callout, Icon, TooltipHost, DirectionalHint, TextField, ITextField } from 'office-ui-fabric-react';
import * as strings from 'PasswordVaultWebPartStrings'; import * as strings from 'PasswordVaultWebPartStrings';
import { getDeepOrDefault, issetDeep, isset } from '@spfxappdev/utility'; import { getDeepOrDefault, issetDeep, isset } from '@spfxappdev/utility';

View File

@ -5,6 +5,7 @@ define([], function() {
"PasswordLabel": "Passwort", "PasswordLabel": "Passwort",
"MasterPasswordLabel": "Master Passwort", "MasterPasswordLabel": "Master Passwort",
"SetMasterPasswordLabel": "Master Passwort", "SetMasterPasswordLabel": "Master Passwort",
"RepeatMasterPasswordLabel": "Master Passwort wiederholen",
"ChangeMasterPasswordLabel": "Master Passwort ändern", "ChangeMasterPasswordLabel": "Master Passwort ändern",
"UsernameLabel": "Benutezrname", "UsernameLabel": "Benutezrname",
"NoteLabel": "Notiz", "NoteLabel": "Notiz",
@ -22,5 +23,8 @@ define([], function() {
"PasswordModuleLabel": "Passwort", "PasswordModuleLabel": "Passwort",
"UsernameModuleLabel": "Benutzername", "UsernameModuleLabel": "Benutzername",
"NoteModuleLabel": "Notiz", "NoteModuleLabel": "Notiz",
"ChangeMasterPasswordButtonText": "Master Passwort ändern",
"ChangeMasterPasswordDialogTitle": "Master Passwort ändern",
"CancelLabel": "Abbrechen"
} }
}); });

View File

@ -5,6 +5,7 @@ define([], function() {
"PasswordLabel": "Password", "PasswordLabel": "Password",
"MasterPasswordLabel": "Master Password", "MasterPasswordLabel": "Master Password",
"SetMasterPasswordLabel": "Master Password", "SetMasterPasswordLabel": "Master Password",
"RepeatMasterPasswordLabel": "Repeat Master Passwort",
"ChangeMasterPasswordLabel": "Change Master Password", "ChangeMasterPasswordLabel": "Change Master Password",
"UsernameLabel": "Username", "UsernameLabel": "Username",
"NoteLabel": "Note", "NoteLabel": "Note",
@ -22,5 +23,8 @@ define([], function() {
"PasswordModuleLabel": "Password", "PasswordModuleLabel": "Password",
"UsernameModuleLabel": "Username", "UsernameModuleLabel": "Username",
"NoteModuleLabel": "Note", "NoteModuleLabel": "Note",
"ChangeMasterPasswordButtonText": "Change Master Passwort",
"ChangeMasterPasswordDialogTitle": "Change Master Passwort",
"CancelLabel": "Cancel"
} }
}); });

View File

@ -4,6 +4,7 @@ declare interface IPasswordVaultWebPartStrings {
PasswordLabel: string; PasswordLabel: string;
MasterPasswordLabel: string; MasterPasswordLabel: string;
SetMasterPasswordLabel: string; SetMasterPasswordLabel: string;
RepeatMasterPasswordLabel: string;
ChangeMasterPasswordLabel: string; ChangeMasterPasswordLabel: string;
UsernameLabel: string; UsernameLabel: string;
NoteLabel: string; NoteLabel: string;
@ -21,6 +22,9 @@ declare interface IPasswordVaultWebPartStrings {
PasswordModuleLabel: string; PasswordModuleLabel: string;
UsernameModuleLabel: string; UsernameModuleLabel: string;
NoteModuleLabel: string; NoteModuleLabel: string;
ChangeMasterPasswordButtonText: string;
ChangeMasterPasswordDialogTitle: string;
CancelLabel: string;
} }
declare module 'PasswordVaultWebPartStrings' { declare module 'PasswordVaultWebPartStrings' {