Commit 7f56a056 authored by Brendan's avatar Brendan

Merge branch '186-make-new-backup-code' into fix-multi-line-form-label

parents e9802d98 7c7a9b8b
Pipeline #38233334 failed with stage
in 5 minutes and 38 seconds
image: registry.gitlab.com/dasch8/angular-ci:latest
image: node:10
variables:
DOCKER_DRIVER: overlay2
COMPOSE: docker-compose -f docker-compose.yml -f docker-compose.ci.yml
CHROME_BIN: chromium-browser
npm_config_cache: $CI_PROJECT_DIR/.npm
stages:
- test
......@@ -12,9 +13,7 @@ stages:
test:
stage: test
cache:
paths:
- node_modules/
image: registry.gitlab.com/dasch8/angular-ci:latest
script:
- yarn install
- yarn run lint
......@@ -24,10 +23,10 @@ build-web-assets:
stage: test
cache:
paths:
- node_modules/
- .npm/
script:
- yarn install
- node --max_old_space_size=6000 node_modules/@angular/cli/bin/ng build --prod --build-optimizer --progress false --source-map
- npm ci
- node --max_old_space_size=6000 node_modules/@angular/cli/bin/ng build --prod --progress false
artifacts:
paths:
- dist/
......@@ -36,14 +35,14 @@ build-ext-assets:
stage: test
cache:
paths:
- node_modules/
- .npm/
script:
- yarn install
- npm ci
- ./set_version.sh
- yarn run build:ext --prod --build-optimizer --progress false
- npm run build:ext --prod --progress false
- bin/remove_eval.sh
- yarn ext:lint
- yarn ext:build
- npm run ext:lint
- npm run ext:build
- mv web-ext-artifacts/*.zip web-ext-artifacts/passit.zip
- mv dist dist-ext
artifacts:
......@@ -53,7 +52,7 @@ build-ext-assets:
build-push-docker:
stage: docker
image: registry.gitlab.com/passit/docker-compose
image: docker:stable
services:
- docker:dind
dependencies:
......@@ -70,7 +69,7 @@ build-push-docker:
deploy-staging:
stage: deploy
image: registry.gitlab.com/passit/docker-compose
image: docker:stable
services:
- docker:dind
only:
......@@ -87,7 +86,7 @@ deploy-staging:
deploy-prod:
stage: deploy
image: registry.gitlab.com/passit/docker-compose
image: docker:stable
services:
- docker:dind
only:
......@@ -124,17 +123,17 @@ deploy-firefox-ext:
- master
when: manual
script:
- yarn add @wext/shipit
- yarn run ext:publish_firefox
- npm install @wext/shipit
- npm run ext:publish_firefox
pages:
stage: pages
cache:
paths:
- node_modules/
- .npm/
script:
- yarn install
- yarn build-storybook -o public
- npm ci
- npm run build-storybook -o public
artifacts:
paths:
- public
......
import { configure } from "@storybook/angular";
console.log("why?????????????????????????Vy");
console.log("why?????????????????????????Vy");
console.log("why?????????????????????????Vy");
console.log("why?????????????????????????Vy");
console.log("why?????????????????????????Vy");
console.log("why?????????????????????????Vy");
// automatically import all files ending in *.stories.ts
const req = require.context("../src/stories", true, /.stories.ts$/);
function loadStories() {
......
......@@ -4,11 +4,11 @@ RUN mkdir /dist
WORKDIR /dist
COPY package.json /dist/package.json
COPY yarn.lock /dist/yarn.lock
RUN yarn install --frozen-lockfile && yarn cache clean
COPY package-lock.json /dist/package-lock.json
RUN npm i
VOLUME /dist/node_modules
ENV PATH /dist/node_modules/.bin:$PATH
COPY . /dist/
ENTRYPOINT ["yarn", "run"]
ENTRYPOINT ["npm", "run"]
......@@ -52,6 +52,10 @@
{
"replace": "src/polyfills.ts",
"with": "src/polyfills.ext.ts"
},
{
"replace": "src/app/store-devtools.ts",
"with": "src/app/store-devtools.prod.ts"
}
]
},
......
#!/bin/sh
find dist -type f -name "*.js" | xargs sed -i 's/new Function(/(/g'
find dist -type f -name "*.js" | xargs sed -i 's/||Function(/\||(/g'
This diff is collapsed.
import { Routes } from "@angular/router";
import { UserService } from "./user";
import { ConfirmEmailGuard } from "./confirm-email/confirm-email.guard";
export const providerDeclarations: any[] = [UserService, ConfirmEmailGuard];
export const routes: Routes = [];
......@@ -10,7 +10,6 @@ import { reducers } from "./account.reducer";
import { SharedModule } from "../shared/shared.module";
import { DirectivesModule } from "../directives";
import { ProgressIndicatorModule } from "../progress-indicator";
import { providerDeclarations } from "./account.common";
import { LoginEffects } from "./account.effects";
import { LoginFormEffects } from "./login/login.effects";
import { RegisterEffects } from "./register/register.effects";
......@@ -24,15 +23,39 @@ import { RegisterContainer } from "./register/register.container";
import { RegisterComponent } from "./register/register.component";
import { LoginComponent } from "./login/login.component";
import { LoginContainer } from "./login/login.container";
import { UserService } from "./user";
import { ConfirmEmailGuard } from "./confirm-email/confirm-email.guard";
import { BackupCodeComponent } from "./backup-code/backup-code.component";
import { BackupCodePdfService } from "./backup-code-pdf.service";
import { ConfirmEmailComponent, ConfirmEmailContainer } from "./confirm-email";
import { ErrorReportingComponent } from "./error-reporting/error-reporting.component";
import { ErrorReportingContainer } from "./error-reporting/error-reporting.container";
import {
ChangePasswordComponent,
ChangePasswordContainer
} from "./change-password";
import { TNSLoginEffects } from "./login/tns-login-effects";
import { MobileMenuModule } from "../mobile-menu";
import { ResetPasswordContainer } from "./reset-password/reset-password.container";
import { ResetPasswordComponent } from "./reset-password/reset-password.component";
export const COMPONENTS = [
LoginContainer,
LoginComponent,
RegisterComponent,
RegisterContainer
RegisterContainer,
ConfirmEmailComponent,
ConfirmEmailContainer,
BackupCodeComponent,
ChangePasswordComponent,
ChangePasswordContainer,
ResetPasswordComponent,
ResetPasswordContainer,
ErrorReportingComponent,
ErrorReportingContainer
];
export const SERVICES = providerDeclarations;
export const SERVICES = [BackupCodePdfService, UserService, ConfirmEmailGuard];
@NgModule({
imports: [
......@@ -43,9 +66,11 @@ export const SERVICES = providerDeclarations;
NgrxFormsModule,
SharedModule,
ProgressIndicatorModule,
MobileMenuModule,
StoreModule.forFeature("account", reducers),
EffectsModule.forFeature([
LoginEffects,
TNSLoginEffects,
LoginFormEffects,
RegisterEffects,
ConfirmEmailEffects,
......
......@@ -42,11 +42,12 @@ import { SetPasswordComponent } from "./reset-password/set-password/set-password
import { SetPasswordContainer } from "./reset-password/set-password/set-password.container";
import { SetPasswordEffects } from "./reset-password/set-password/set-password.effects";
import { ServerSelectComponent } from "./shared/server-select.component";
import { providerDeclarations } from "./account.common";
import { RegisterContainer } from "./register/register.container";
import { RegisterComponent } from "./register/register.component";
import { LoginComponent } from "./login/login.component";
import { LoginContainer } from "./login/login.container";
import { ConfirmEmailGuard } from "./confirm-email/confirm-email.guard";
import { UserService } from "./user";
export const COMPONENTS = [
LoginContainer,
......@@ -77,7 +78,7 @@ export const COMPONENTS = [
ServerSelectComponent
];
export const SERVICES = providerDeclarations.concat([BackupCodePdfService]);
export const SERVICES = [BackupCodePdfService, UserService, ConfirmEmailGuard];
@NgModule({
imports: [
......
import { Injectable } from "@angular/core";
@Injectable({
providedIn: "root"
})
export class BackupCodePdfService {
constructor() {}
/**
* Downloads PDF containing backup code string and matching QR Code
* @param code: 32 character backupcode string
*/
download(code: string) {}
}
<DockLayout stretchLastChild="true">
<StackLayout dock="bottom" class="auth-actions">
<FlexboxLayout
flexDirection="row"
alignItems="center"
justifyContent="space-between">
<app-button
type="text"
text="Skip (not recommended)"
(tap)="goToNext.emit()"
></app-button>
<app-button
width="150"
text="Download"
(tap)="download()"
></app-button>
</FlexboxLayout>
</StackLayout>
<ScrollView>
<StackLayout class="auth-form-body">
<StackLayout class="auth-header">
<app-heading text="Backup Code"></app-heading>
</StackLayout>
<FormattedString>
<Span text="Your backup code is the "></Span>
<Span text="only" class="font-weight-bold"></Span>
<Span text=" way to recover your account if you forget your password."></Span>
</FormattedString>
<Label
class="text-label m-b-30"
text="Download it, print it out, and save it someplace safe."
textWrap="true"
></Label>
</StackLayout>
</ScrollView>
</DockLayout>
<ns-action-bar-container></ns-action-bar-container>
<GridLayout>
<FlexboxLayount class="page">
<StackLayout orientation="vertical" class="form">
<Label text="Change Account Password"></Label>
<Label [text]="nonFieldErrors"></Label>
<app-non-field-messages [messages]="nonFieldErrors"></app-non-field-messages>
<TextField
[ngrxFormControlState]="form.controls.oldPassword"
hint="Current Password"
autocorrect="false"
autocapitalizationType="none"
secure="true"
></TextField>
<TextField
[ngrxFormControlState]="form.controls.newPassword"
hint="New Password"
autocorrect="false"
autocapitalizationType="none"
secure="true"
></TextField>
<TextField
[ngrxFormControlState]="form.controls.newPasswordConfirm"
hint="New Password (Confirm)"
autocorrect="false"
autocapitalizationType="none"
secure="true"
returnKeyType="done"
(returnPress)="onSubmit()"
></TextField>
<StackLayout class="p-b-10" *ngIf="form.isInvalid && form.isSubmitted && form.errors._newPassword">
<Label *ngIf="form.errors._newPassword.required" text="You must have a password!"></Label>
<Label
*ngIf="form.errors._newPassword.minLength"
text="Password must be at least {{ form.errors._newPassword.minLength.minLength }} characters long!!"
></Label>
<Label
*ngIf="form.errors._newPassword.hasUniqueChars"
text="Password must have more than 5 unique characters."
></Label>
<Label
*ngIf="form.errors._newPassword.notNumeric"
text="Password must not be only numbers."
></Label>
<Label
*ngIf="form.errors._newPassword.notEqualTo"
text="New password is the same as the old password."
></Label>
</StackLayout>
<StackLayout class="p-b-10" *ngIf="form.isInvalid && form.isSubmitted && form.errors._newPasswordConfirm">
<Label
*ngIf="form.errors._newPasswordConfirm.equalTo && form.controls.showConfirm.value"
text="Passwords don't match."
></Label>
</StackLayout>
<Button
class="submit-button"
text="Change Password"
(tap)="onSubmit()"
></Button>
</StackLayout>
</FlexboxLayount>
</GridLayout>
import { Component, EventEmitter, Input, Output } from "@angular/core";
import { FormGroupState, MarkAsSubmittedAction } from "ngrx-forms";
import { ActionsSubject } from "@ngrx/store";
import { IChangePasswordForm } from "../change-password/change-password.reducer";
@Component({
selector: "change-password",
moduleId: module.id,
templateUrl: "./change-password.component.html"
})
export class ChangePasswordComponent {
@Input() form: FormGroupState<IChangePasswordForm>;
@Input() hasStarted: boolean;
@Input() hasFinished: boolean;
@Input() nonFieldErrors: string[];
@Output() changePassword = new EventEmitter();
@Output() toggleConfirm = new EventEmitter();
constructor(private actionsSubject: ActionsSubject) {}
onSubmit() {
if (this.form.isValid) {
this.changePassword.emit();
} else if (this.form.isUnsubmitted) {
this.actionsSubject.next(new MarkAsSubmittedAction(this.form.id));
}
}
}
<DockLayout stretchLastChild="true">
<StackLayout dock="bottom" class="auth-actions">
<FlexboxLayout
flexDirection="row"
alignItems="center"
justifyContent="space-between">
<app-button
type="text"
text="Log Out"
(tap)="logOut.emit()"
></app-button>
<app-button
width="150"
text="Get Started"
[isEnabled]="!hasStarted"
(tap)="submit()"
></app-button>
</FlexboxLayout>
</StackLayout>
<ScrollView>
<StackLayout class="auth-form-body">
<StackLayout class="auth-header">
<app-heading text="Confirm Email"></app-heading>
</StackLayout>
<Label
class="text-label m-b-30"
text="We just sent an email to the address you gave us. Click the link in the message or enter the code into the box below to confirm your email and start using Passit."
textWrap="true"
></Label>
<app-non-field-messages *ngIf="confirmCodeMessage" [messages]="[confirmCodeMessage]"></app-non-field-messages>
<StackLayout class="m-b-10">
<Label class="text-label" text="Code"></Label>
<TextField
#codeInput
autocapitalizationType="none"
autocorrect="false"
returnKeyType="done"
width="100"
horizontalAlignment="left"
[class.text-field--error]="errorMessage"
[(ngModel)]="code"
(returnPress)="submit()"
class="input text-field"
></TextField>
</StackLayout>
<Label
*ngIf="errorMessage"
[text]="errorMessage"
></Label>
<progress-indicator
[inProgress]="hasStarted"
inProgressText="Confirming email"
[completed]="hasFinished"
completedText="Confirmed email"
></progress-indicator>
</StackLayout>
</ScrollView>
</DockLayout>
\ No newline at end of file
import {
Component,
EventEmitter,
Input,
Output,
ViewChild,
ElementRef,
OnInit
} from "@angular/core";
/**
* Confirm email component
*/
@Component({
selector: "confirm-email-component",
moduleId: module.id,
templateUrl: "./confirm-email.component.html",
styleUrls: ["./confirm-email.styles.css",
"../shared/auth.styles.css"],
})
export class ConfirmEmailComponent implements OnInit {
@ViewChild("codeInput") codeInput: ElementRef;
/** The error message, passed from the container to the template */
@Input() errorMessage: string;
@Input() confirmCodeMessage: string;
/** The confirmation code. Can be pulled as a param from the URL or entered in the text field. */
@Input() code: string;
/** Lets the template know if a server call has started */
@Input() hasStarted: boolean;
/** Lets the template know if a server call has finished (successfully) */
@Input() hasFinished: boolean;
/** Lets the template know if the form is inline with the register form or not */
@Input() inline: boolean;
/** Emits the confirmation code to the container and triggers the server call */
@Output() confirmEmail = new EventEmitter<string>();
@Output() resetRegisterCode = new EventEmitter();
@Output() logOut = new EventEmitter();
/**
* The form uses this to trigger the confirmEmail emitter
*
* param form The code used to confirm the email address
*/
ngOnInit() {
this.codeInput.nativeElement.focus();
}
submit() {
this.confirmEmail.emit(this.code);
}
onClick() {
this.resetRegisterCode.emit();
}
}
/* If confirm email ever gets ngrxified, this can be removed */
.text-label {
color: #413741;
font-size: 14;
letter-spacing: 0.04;
line-height: 1.333;
}
.text-field {
padding: 10 0;
border-bottom-width: 2;
border-bottom-color: #6F989E;
}
.text-field::highlighted {
border-bottom-color: #0092A8;
}
.text-field.ng-invalid::highlighted,
.text-field--error {
border-bottom-color: #B92855;
}
<ns-action-bar-container></ns-action-bar-container>
<DockLayout stretchLastChild="true">
<FlexboxLayout dock="bottom" class="m-x-10 m-y-25" flexDirection="row" justifyContent="flex-end">
<app-button
text="Save"
(tap)="submit.emit()"
></app-button>
</FlexboxLayout>
<ScrollView>
<StackLayout class="p-x-20 p-y-25">
<StackLayout class="m-b-30">
<app-heading text="Error Reporting"></app-heading>
</StackLayout>
<Label
class="text-label m-b-10"
text="For your safety and privacy, Passit has no in-app tracking by default. However, the Passit developers benefit from receiving error reports, which requires this sort of&nbsp;tracking."
textWrap="true"
></Label>
<Label
class="text-label m-b-20"
text="If you are willing to opt in to share anonymous information, please do! It will help make Passit better for&nbsp;everyone."
textWrap="true"
></Label>
<app-checkbox
title="Enable error reporting"
[control]="form.controls.optInErrorReporting"
></app-checkbox>
</StackLayout>
</ScrollView>
</DockLayout>
......@@ -43,7 +43,12 @@
>
Password
</app-form-label>
<a class="text-link text-link--caret form-field__label-link" href="javascript:void(0)" [routerLink]="['/reset-password']" tabindex="8"><span class="u-visible--all-but-small">Forgot? </span>Recover&nbsp;your&nbsp;account</a>
<aside-link
text="Forgot? Recover your account"
tabindex="8"
[link]="['/reset-password']"
></aside-link>
<!--a class="text-link text-link--caret form-field__label-link" href="javascript:void(0)" [routerLink]="['/reset-password']" tabindex="8"><span class="u-visible--all-but-small">Forgot? </span>Recover&nbsp;your&nbsp;account</a-->
</div>
<input
type="password"
......
......@@ -31,7 +31,6 @@
returnKeyType="next"
[isFormSubmitted]="form.isSubmitted"
[ngrxFormControl]="form.controls.email"
(returnPress)="focusPassword()"
></app-text-field>
<Label
......@@ -54,7 +53,7 @@
[ngrxFormControl]="form.controls.password"
(returnPress)="onSubmit()"
></app-text-field>
<Label
*ngIf="form.errors._password && form.isSubmitted"
class="text-label text-label--error"
......@@ -62,6 +61,12 @@
textWrap="true"
></Label>
<aside-link
text="Forgot? Recover your account"
tabindex="8"
[link]="['/reset-password']"
></aside-link>
<progress-indicator
[inProgress]="hasLoginStarted"
[completed]="hasLoginFinished"
......
import {
Component,
EventEmitter,
Input,
Output,
ViewChild,
ElementRef
} from "@angular/core";
import { FormGroupState, MarkAsSubmittedAction } from "ngrx-forms";
import { ActionsSubject } from "@ngrx/store";
import { ILoginForm } from "./interfaces";
@Component({
selector: "login-component",
moduleId: module.id,
templateUrl: "./login.component.html",
styleUrls: ["../shared/auth.styles.css"]
})
export class LoginComponent {
@Input() form: FormGroupState<ILoginForm>;