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
19 changes: 18 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,19 @@
node_modules
scripts
scripts
actions
.yarn
.vscode
.sass-cache
.husky
.github
.git
**/dist
**/coverage
**/node_modules
packages/components
packages/docs
packages/mobile/android
packages/mobile/ios
packages/mobile/html
packages/snjs/mocha
*.d.ts
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"extends": ["./node_modules/@standardnotes/config/src/.eslintrc"],
"ignorePatterns": [".eslintrc.js", "*.webpack.*.js", "webpack-defaults.js", "jest.config.js", "__mocks__"]
"ignorePatterns": [".eslintrc.js", "*.webpack.*.js", "webpack-defaults.js", "jest.config.js", "__mocks__", "**/**/coverage"]
}
1 change: 1 addition & 0 deletions packages/api/.eslintignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules
dist
coverage
3 changes: 3 additions & 0 deletions packages/desktop/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
dist
jsign
3 changes: 2 additions & 1 deletion packages/mobile/.eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ ios
e2e
android
fastlane
WebFrame
WebFrame
__tests__
2 changes: 1 addition & 1 deletion packages/mobile/src/Lib/ApplicationState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,7 @@ export class ApplicationState extends ApplicationService {
).includes(state)
}

private async getScreenshotPrivacyEnabled(): Promise<boolean | undefined> {
private async getScreenshotPrivacyEnabled(): Promise<boolean> {
return this.application.getMobileScreenshotPrivacyEnabled()
}

Expand Down
7 changes: 6 additions & 1 deletion packages/mobile/src/Lib/Interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ export class MobileDevice implements MobileDeviceInterface {
;(this.stateObserverService as unknown) = undefined
}

consoleLog(...args: any[]): void {
// eslint-disable-next-line no-console
console.log(args)
}

async setLegacyRawKeychainValue(value: LegacyRawKeychainValue): Promise<void> {
await Keychain.setKeys(value)
}
Expand Down Expand Up @@ -378,7 +383,7 @@ export class MobileDevice implements MobileDeviceInterface {
await Keychain.clearKeys()
}

async setAndroidScreenshotPrivacy(enable: boolean): Promise<void> {
setAndroidScreenshotPrivacy(enable: boolean): void {
if (Platform.OS === 'android') {
enable ? FlagSecure.activate() : FlagSecure.deactivate()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ export const SecuritySection = (props: Props) => {
useEffect(() => {
let mounted = true
const getHasScreenshotPrivacy = async () => {
const hasScreenshotPrivacyEnabled = (await application?.getMobileScreenshotPrivacyEnabled()) ?? true
const hasScreenshotPrivacyEnabled = application?.getMobileScreenshotPrivacyEnabled()
if (mounted) {
setHasScreenshotPrivacy(hasScreenshotPrivacyEnabled)
}
}
void getHasScreenshotPrivacy()
const getHasBiometrics = async () => {
const appHasBiometrics = await application!.hasBiometrics()
const appHasBiometrics = application!.hasBiometrics()
if (mounted) {
setHasBiometrics(appHasBiometrics)
}
Expand Down
1 change: 1 addition & 0 deletions packages/responses/.eslintignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules
dist
coverage
3 changes: 2 additions & 1 deletion packages/services/src/Domain/Device/MobileDeviceInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ export interface MobileDeviceInterface extends DeviceInterface {

getRawKeychainValue(): Promise<RawKeychainValue | undefined>
getDeviceBiometricsAvailability(): Promise<boolean>
setAndroidScreenshotPrivacy(enable: boolean): Promise<void>
setAndroidScreenshotPrivacy(enable: boolean): void
authenticateWithBiometrics(): Promise<boolean>
hideMobileInterfaceFromScreenshots(): void
stopHidingMobileInterfaceFromScreenshots(): void
consoleLog(...args: any[]): void
}
6 changes: 5 additions & 1 deletion packages/snjs/.eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@ node_modules
dist
test
*.config.js
mocha/**/*
mocha/**/*
coverage
e2e-server.js
jest-global.ts
webpack.*.js
25 changes: 13 additions & 12 deletions packages/snjs/lib/Application/Application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ export class SNApplication
)
}
}

await this.handleStage(ExternalServices.ApplicationStage.StorageDecrypted_09)

this.apiService.loadHost()
Expand Down Expand Up @@ -929,28 +930,28 @@ export class SNApplication
return this.deinit(this.getDeinitMode(), DeinitSource.Lock)
}

async setBiometricsTiming(timing: MobileUnlockTiming) {
setBiometricsTiming(timing: MobileUnlockTiming) {
return this.protectionService.setBiometricsTiming(timing)
}

async getMobileScreenshotPrivacyEnabled(): Promise<boolean | undefined> {
getMobileScreenshotPrivacyEnabled(): boolean {
return this.protectionService.getMobileScreenshotPrivacyEnabled()
}

async getMobilePasscodeTiming(): Promise<MobileUnlockTiming | undefined> {
return this.getValue(StorageKey.MobilePasscodeTiming, StorageValueModes.Nonwrapped) as Promise<
MobileUnlockTiming | undefined
>
setMobileScreenshotPrivacyEnabled(isEnabled: boolean) {
return this.protectionService.setMobileScreenshotPrivacyEnabled(isEnabled)
}

async getMobileBiometricsTiming(): Promise<MobileUnlockTiming | undefined> {
return this.getValue(StorageKey.MobileBiometricsTiming, StorageValueModes.Nonwrapped) as Promise<
MobileUnlockTiming | undefined
>
getMobilePasscodeTiming(): MobileUnlockTiming | undefined {
return this.getValue(StorageKey.MobilePasscodeTiming, StorageValueModes.Nonwrapped) as
| MobileUnlockTiming
| undefined
}

async setMobileScreenshotPrivacyEnabled(isEnabled: boolean) {
return this.protectionService.setMobileScreenshotPrivacyEnabled(isEnabled)
getMobileBiometricsTiming(): MobileUnlockTiming | undefined {
return this.getValue(StorageKey.MobileBiometricsTiming, StorageValueModes.Nonwrapped) as
| MobileUnlockTiming
| undefined
}

async loadMobileUnlockTiming() {
Expand Down
22 changes: 11 additions & 11 deletions packages/snjs/lib/Services/Protection/ProtectionService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,36 +257,36 @@ export class SNProtectionService extends AbstractService<ProtectionEvent> implem
]
}

private async getBiometricsTiming(): Promise<MobileUnlockTiming | undefined> {
return this.storageService.getValue<Promise<MobileUnlockTiming | undefined>>(
private getBiometricsTiming(): MobileUnlockTiming | undefined {
return this.storageService.getValue<MobileUnlockTiming | undefined>(
StorageKey.MobileBiometricsTiming,
StorageValueModes.Nonwrapped,
)
}

private async getPasscodeTiming(): Promise<MobileUnlockTiming | undefined> {
return this.storageService.getValue<Promise<MobileUnlockTiming | undefined>>(
private getPasscodeTiming(): MobileUnlockTiming | undefined {
return this.storageService.getValue<MobileUnlockTiming | undefined>(
StorageKey.MobilePasscodeTiming,
StorageValueModes.Nonwrapped,
)
}

async setBiometricsTiming(timing: MobileUnlockTiming) {
await this.storageService.setValue(StorageKey.MobileBiometricsTiming, timing, StorageValueModes.Nonwrapped)
this.storageService.setValue(StorageKey.MobileBiometricsTiming, timing, StorageValueModes.Nonwrapped)
this.mobileBiometricsTiming = timing
}

async setMobileScreenshotPrivacyEnabled(isEnabled: boolean) {
setMobileScreenshotPrivacyEnabled(isEnabled: boolean) {
return this.storageService.setValue(StorageKey.MobileScreenshotPrivacyEnabled, isEnabled, StorageValueModes.Default)
}

async getMobileScreenshotPrivacyEnabled(): Promise<boolean | undefined> {
return this.storageService.getValue(StorageKey.MobileScreenshotPrivacyEnabled, StorageValueModes.Default)
getMobileScreenshotPrivacyEnabled(): boolean {
return this.storageService.getValue(StorageKey.MobileScreenshotPrivacyEnabled, StorageValueModes.Default, false)
}

async loadMobileUnlockTiming() {
this.mobilePasscodeTiming = await this.getPasscodeTiming()
this.mobileBiometricsTiming = await this.getBiometricsTiming()
loadMobileUnlockTiming(): void {
this.mobilePasscodeTiming = this.getPasscodeTiming()
this.mobileBiometricsTiming = this.getBiometricsTiming()
}

private async validateOrRenewSession(
Expand Down
33 changes: 33 additions & 0 deletions packages/snjs/lib/Services/Storage/DiskStorageService.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { DiskStorageService } from './DiskStorageService'

import { InternalEventBus, DeviceInterface, InternalEventBusInterface } from '@standardnotes/services'
import { Environment } from '@standardnotes/models'

describe('diskStorageService', () => {
let storageService: DiskStorageService
let internalEventBus: InternalEventBusInterface
let device: DeviceInterface

beforeEach(() => {
internalEventBus = {} as jest.Mocked<InternalEventBus>
device = {} as jest.Mocked<DeviceInterface>

storageService = new DiskStorageService(device, 'test', Environment.Desktop, internalEventBus)
})

it('setInitialValues should set unwrapped values as wrapped value if wrapped value is not encrypted', async () => {
storageService.isStorageWrapped = jest.fn().mockReturnValue(false)

await storageService['setInitialValues']({
wrapped: { content: { foo: 'bar' } } as never,
nonwrapped: {},
unwrapped: { bar: 'zoo' },
})

expect(storageService['values']).toEqual({
wrapped: { content: { foo: 'bar' } } as never,
nonwrapped: {},
unwrapped: { bar: 'zoo', foo: 'bar' },
})
})
})
17 changes: 10 additions & 7 deletions packages/snjs/lib/Services/Storage/DiskStorageService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,21 +112,24 @@ export class DiskStorageService extends Services.AbstractService implements Serv
const value = await this.deviceInterface.getRawStorageValue(this.getPersistenceKey())
const values = value ? JSON.parse(value as string) : undefined

this.setInitialValues(values)
await this.setInitialValues(values)
}

/**
* Called by platforms with the value they load from disk,
* after they handle initializeFromDisk
*/
private setInitialValues(values?: Services.StorageValuesObject) {
private async setInitialValues(values?: Services.StorageValuesObject) {
const sureValues = values || this.defaultValuesObject()

if (!sureValues[Services.ValueModesKeys.Unwrapped]) {
sureValues[Services.ValueModesKeys.Unwrapped] = {}
}

this.values = sureValues

if (!this.isStorageWrapped()) {
this.values[Services.ValueModesKeys.Unwrapped] = {
...(this.values[Services.ValueModesKeys.Wrapped].content as object),
...this.values[Services.ValueModesKeys.Unwrapped],
}
}
}

public isStorageWrapped(): boolean {
Expand Down Expand Up @@ -370,7 +373,7 @@ export class DiskStorageService extends Services.AbstractService implements Serv
* Clears simple values from storage only. Does not affect payloads.
*/
async clearValues() {
this.setInitialValues()
await this.setInitialValues()
await this.immediatelyPersistValuesToDisk()
}

Expand Down
2 changes: 1 addition & 1 deletion packages/snjs/mocha/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module.exports = {
extends: ['../.eslintrc.js'],
extends: ['../.eslintrc'],
globals: {
chai: true,
chaiAsPromised: true,
Expand Down
4 changes: 4 additions & 0 deletions packages/web/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
dist
node_modules
web.webpack-defaults.js
coverage
4 changes: 3 additions & 1 deletion packages/web/.eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
"__mocks__",
"src/components",
"src/favicon",
"src/vendor"
"src/vendor",
"coverage",
"*.config.js"
],
"rules": {
"standard/no-callback-literal": 0, // Disable this as we have too many callbacks relying on literals
Expand Down
9 changes: 7 additions & 2 deletions packages/web/src/javascripts/Application/Application.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ export class WebApplication extends SNApplication implements WebApplicationInter

if (this.isNativeMobileWeb()) {
this.mobileWebReceiver = new MobileWebReceiver(this)

// eslint-disable-next-line no-console
console.log = (...args) => {
this.mobileDevice.consoleLog(...args)
}
}

this.onVisibilityChange = () => {
Expand Down Expand Up @@ -228,15 +233,15 @@ export class WebApplication extends SNApplication implements WebApplicationInter
async handleMobileGainingFocusEvent(): Promise<void> {}

async handleMobileLosingFocusEvent(): Promise<void> {
if (await this.getMobileScreenshotPrivacyEnabled()) {
if (this.getMobileScreenshotPrivacyEnabled()) {
this.mobileDevice.stopHidingMobileInterfaceFromScreenshots()
}

await this.lockApplicationAfterMobileEventIfApplicable()
}

async handleMobileResumingFromBackgroundEvent(): Promise<void> {
if (await this.getMobileScreenshotPrivacyEnabled()) {
if (this.getMobileScreenshotPrivacyEnabled()) {
this.mobileDevice.hideMobileInterfaceFromScreenshots()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const BiometricsLock = ({ application }: Props) => {

useEffect(() => {
const getHasBiometrics = async () => {
const appHasBiometrics = await application.hasBiometrics()
const appHasBiometrics = application.hasBiometrics()
setHasBiometrics(appHasBiometrics)
}

Expand Down Expand Up @@ -50,7 +50,7 @@ const BiometricsLock = ({ application }: Props) => {
await disableBiometrics()
} else {
setHasBiometrics(true)
await application.enableBiometrics()
application.enableBiometrics()
await setBiometricsTimingValue(MobileUnlockTiming.OnQuit)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,19 @@ type Props = {
}

const MultitaskingPrivacy = ({ application }: Props) => {
const [hasScreenshotPrivacy, setHasScreenshotPrivacy] = useState<boolean | undefined>(false)
const [hasScreenshotPrivacy, setHasScreenshotPrivacy] = useState<boolean>(false)

useEffect(() => {
const getHasScreenshotPrivacy = async () => {
const hasScreenshotPrivacyEnabled = (await application.getMobileScreenshotPrivacyEnabled()) ?? true
setHasScreenshotPrivacy(hasScreenshotPrivacyEnabled)
}
void getHasScreenshotPrivacy()
const hasScreenshotPrivacyEnabled = application.getMobileScreenshotPrivacyEnabled()
setHasScreenshotPrivacy(hasScreenshotPrivacyEnabled)
}, [application])

const onScreenshotPrivacyPress = async () => {
const enable = !hasScreenshotPrivacy
setHasScreenshotPrivacy(enable)

await application.setMobileScreenshotPrivacyEnabled(enable)
await (application.deviceInterface as MobileDeviceInterface).setAndroidScreenshotPrivacy(enable)
application.setMobileScreenshotPrivacyEnabled(enable)
;(application.deviceInterface as MobileDeviceInterface).setAndroidScreenshotPrivacy(enable)
}

const screenshotPrivacyFeatureText = isIOS() ? 'Multitasking Privacy' : 'Multitasking/Screenshot Privacy'
Expand Down