From 95ffae0e3875bd055bbb0d357754b402c68b6c16 Mon Sep 17 00:00:00 2001 From: Mike Maietta Date: Fri, 12 Mar 2021 18:27:18 -0800 Subject: [PATCH 1/3] Adding conditional binding so that we can retain type-safety of the import for things like `permissions.AuthType` as function params with a generic import that is platform-agnostic. Enhancement and fixes: #23 Adding additional test to run on a separate linux node --- .github/workflows/test.yml | 7 ++++-- README.md | 2 ++ index.js | 30 ++++++++++++++++---------- package.json | 4 ++-- test/module.spec.js | 44 ++++++++++++++++++++++++++++++-------- 5 files changed, 63 insertions(+), 24 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f5278fa..55af15b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,14 +10,17 @@ on: jobs: build: - runs-on: macOS-latest + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-latest, ubuntu-latest] steps: - uses: actions/checkout@master - name: Use Node.js 14.x uses: actions/setup-node@v1 with: version: 14.x - - name: npm install, build, and test + - name: npm install, build, and test (${{ matrix.os }}) run: | npm install npm test \ No newline at end of file diff --git a/README.md b/README.md index 6eb6bdd..3afe22e 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ This native Node.js module allows you to manage an app's access to: * Speech Recognition * Protected Folders +Note: Always will return `undefined` when imported on a non-Mac platform + ## API ## `permissions.getAuthStatus(type)` diff --git a/index.js b/index.js index 1bef735..5e8b945 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,21 @@ -const permissions = require('bindings')('permissions.node') +const nonMacResponse = () => undefined +const stub = { + askForCalendarAccess: nonMacResponse, + askForContactsAccess: nonMacResponse, + askForFoldersAccess: nonMacResponse, + askForFullDiskAccess: nonMacResponse, + askForRemindersAccess: nonMacResponse, + askForCameraAccess: nonMacResponse, + askForMicrophoneAccess: nonMacResponse, + askForPhotosAccess: nonMacResponse, + askForSpeechRecognitionAccess: nonMacResponse, + askForScreenCaptureAccess: nonMacResponse, + askForAccessibilityAccess: nonMacResponse, + getAuthStatus: nonMacResponse, +} + +const os = require('os') +const permissions = os.platform() === 'darwin' ? require('bindings')('permissions.node') : stub function getAuthStatus(type) { const validTypes = [ @@ -34,16 +51,7 @@ function askForFoldersAccess(folder) { } module.exports = { - askForCalendarAccess: permissions.askForCalendarAccess, - askForContactsAccess: permissions.askForContactsAccess, + ...permissions, askForFoldersAccess, - askForFullDiskAccess: permissions.askForFullDiskAccess, - askForRemindersAccess: permissions.askForRemindersAccess, - askForCameraAccess: permissions.askForCameraAccess, - askForMicrophoneAccess: permissions.askForMicrophoneAccess, - askForPhotosAccess: permissions.askForPhotosAccess, - askForSpeechRecognitionAccess: permissions.askForSpeechRecognitionAccess, - askForScreenCaptureAccess: permissions.askForScreenCaptureAccess, - askForAccessibilityAccess: permissions.askForAccessibilityAccess, getAuthStatus, } diff --git a/package.json b/package.json index f87dddc..5e9a978 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,8 @@ "scripts": { "build": "node-gyp rebuild", "clean": "node-gyp clean", - "lint": "prettier --check index.js", - "format": "clang-format -i permissions.mm && prettier --write index.js", + "lint": "prettier --check index.js test/module.spec.js", + "format": "clang-format -i permissions.mm && prettier --write index.js test/module.spec.js", "test": "./node_modules/.bin/mocha --reporter spec" }, "repository": { diff --git a/test/module.spec.js b/test/module.spec.js index f6cac6e..df416f5 100644 --- a/test/module.spec.js +++ b/test/module.spec.js @@ -1,18 +1,19 @@ const { expect } = require('chai') -const { - askForFoldersAccess, - getAuthStatus, -} = require('../index') +const permissions = require('../index') + +const isMac = process.platform === 'darwin' +it.ifMac = isMac ? it : it.skip +it.ifNotMac = isMac ? it.skip : it describe('node-mac-permissions', () => { describe('getAuthStatus()', () => { it('should throw on invalid types', () => { expect(() => { - getAuthStatus('bad-type') + permissions.getAuthStatus('bad-type') }).to.throw(/bad-type is not a valid type/) }) - it('should return a string', () => { + it.ifMac('should return a string', () => { const types = [ 'contacts', 'calendar', @@ -24,12 +25,12 @@ describe('node-mac-permissions', () => { 'microphone', 'accessibility', 'location', - 'screen' + 'screen', ] const statuses = ['not determined', 'denied', 'authorized', 'restricted'] for (const type of types) { - const status = getAuthStatus(type) + const status = permissions.getAuthStatus(type) expect(statuses).to.contain(status) } }) @@ -38,8 +39,33 @@ describe('node-mac-permissions', () => { describe('askForFoldersAccess()', () => { it('should throw on invalid types', () => { expect(() => { - askForFoldersAccess('bad-type') + permissions.askForFoldersAccess('bad-type') }).to.throw(/bad-type is not a valid protected folder/) }) }) + + describe('conditional binding', () => { + it.ifNotMac('always return undefined for non-mac OS', async () => { + const asyncModuleExports = [ + 'askForCalendarAccess', + 'askForContactsAccess', + 'askForFullDiskAccess', + 'askForRemindersAccess', + 'askForCameraAccess', + 'askForMicrophoneAccess', + 'askForPhotosAccess', + 'askForSpeechRecognitionAccess', + 'askForScreenCaptureAccess', + 'askForAccessibilityAccess', + ] + + for (const func of asyncModuleExports) { + const auth = await permissions[func]() + expect(auth).to.be.undefined + } + + expect(permissions.getAuthStatus('contacts')).to.be.undefined + expect(permissions.askForFoldersAccess('desktop')).to.be.undefined + }) + }) }) From c53bda2ee78aff5934ee7ae4da2961d1922366b7 Mon Sep 17 00:00:00 2001 From: Mike Maietta Date: Fri, 12 Mar 2021 18:40:02 -0800 Subject: [PATCH 2/3] Updating deprecated config var --- .github/workflows/lint.yml | 2 +- .github/workflows/test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index da7a8d6..979d8a0 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -16,7 +16,7 @@ jobs: - name: Use Node.js 14.x uses: actions/setup-node@v1 with: - version: 14.x + node-version: 14.x - name: Lint run: | npm install diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 55af15b..e69254a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,7 +19,7 @@ jobs: - name: Use Node.js 14.x uses: actions/setup-node@v1 with: - version: 14.x + node-version: 14.x - name: npm install, build, and test (${{ matrix.os }}) run: | npm install From b1d93996510109341058e26a24d9dc2d35e22857 Mon Sep 17 00:00:00 2001 From: Mike Maietta Date: Fri, 12 Mar 2021 18:27:18 -0800 Subject: [PATCH 3/3] Adding conditional binding so that we can retain type-safety of the import for things like `permissions.AuthType` as function params with a generic import that is platform-agnostic. Enhancement and fixes: #23 Adding additional test to run on a separate linux node --- .github/workflows/lint.yml | 2 +- .github/workflows/test.yml | 9 +++++--- README.md | 2 ++ index.js | 30 +++++++++++++++---------- package.json | 4 ++-- test/module.spec.js | 45 ++++++++++++++++++++++++++++++-------- 6 files changed, 66 insertions(+), 26 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index da7a8d6..979d8a0 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -16,7 +16,7 @@ jobs: - name: Use Node.js 14.x uses: actions/setup-node@v1 with: - version: 14.x + node-version: 14.x - name: Lint run: | npm install diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f5278fa..e69254a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,14 +10,17 @@ on: jobs: build: - runs-on: macOS-latest + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-latest, ubuntu-latest] steps: - uses: actions/checkout@master - name: Use Node.js 14.x uses: actions/setup-node@v1 with: - version: 14.x - - name: npm install, build, and test + node-version: 14.x + - name: npm install, build, and test (${{ matrix.os }}) run: | npm install npm test \ No newline at end of file diff --git a/README.md b/README.md index 6eb6bdd..3afe22e 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ This native Node.js module allows you to manage an app's access to: * Speech Recognition * Protected Folders +Note: Always will return `undefined` when imported on a non-Mac platform + ## API ## `permissions.getAuthStatus(type)` diff --git a/index.js b/index.js index 1bef735..7c6886f 100644 --- a/index.js +++ b/index.js @@ -1,4 +1,21 @@ -const permissions = require('bindings')('permissions.node') +const nonMacResponse = () => undefined +const stub = { + askForCalendarAccess: nonMacResponse, + askForContactsAccess: nonMacResponse, + askForFoldersAccess: nonMacResponse, + askForFullDiskAccess: nonMacResponse, + askForRemindersAccess: nonMacResponse, + askForCameraAccess: nonMacResponse, + askForMicrophoneAccess: nonMacResponse, + askForPhotosAccess: nonMacResponse, + askForSpeechRecognitionAccess: nonMacResponse, + askForScreenCaptureAccess: nonMacResponse, + askForAccessibilityAccess: nonMacResponse, + getAuthStatus: nonMacResponse, +} + +const { platform } = require('os') +const permissions = platform() === 'darwin' ? require('bindings')('permissions.node') : stub function getAuthStatus(type) { const validTypes = [ @@ -34,16 +51,7 @@ function askForFoldersAccess(folder) { } module.exports = { - askForCalendarAccess: permissions.askForCalendarAccess, - askForContactsAccess: permissions.askForContactsAccess, + ...permissions, askForFoldersAccess, - askForFullDiskAccess: permissions.askForFullDiskAccess, - askForRemindersAccess: permissions.askForRemindersAccess, - askForCameraAccess: permissions.askForCameraAccess, - askForMicrophoneAccess: permissions.askForMicrophoneAccess, - askForPhotosAccess: permissions.askForPhotosAccess, - askForSpeechRecognitionAccess: permissions.askForSpeechRecognitionAccess, - askForScreenCaptureAccess: permissions.askForScreenCaptureAccess, - askForAccessibilityAccess: permissions.askForAccessibilityAccess, getAuthStatus, } diff --git a/package.json b/package.json index f87dddc..097c5fb 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,8 @@ "scripts": { "build": "node-gyp rebuild", "clean": "node-gyp clean", - "lint": "prettier --check index.js", - "format": "clang-format -i permissions.mm && prettier --write index.js", + "lint": "prettier --check '**/*.js'", + "format": "clang-format -i permissions.mm && prettier --write '**/*.js'", "test": "./node_modules/.bin/mocha --reporter spec" }, "repository": { diff --git a/test/module.spec.js b/test/module.spec.js index f6cac6e..6399b3f 100644 --- a/test/module.spec.js +++ b/test/module.spec.js @@ -1,18 +1,20 @@ const { expect } = require('chai') -const { - askForFoldersAccess, - getAuthStatus, -} = require('../index') +const permissions = require('../index') + +const { platform } = require('os') +const isMac = platform() === 'darwin' +it.ifMac = isMac ? it : it.skip +it.ifNotMac = isMac ? it.skip : it describe('node-mac-permissions', () => { describe('getAuthStatus()', () => { it('should throw on invalid types', () => { expect(() => { - getAuthStatus('bad-type') + permissions.getAuthStatus('bad-type') }).to.throw(/bad-type is not a valid type/) }) - it('should return a string', () => { + it.ifMac('should return a string', () => { const types = [ 'contacts', 'calendar', @@ -24,12 +26,12 @@ describe('node-mac-permissions', () => { 'microphone', 'accessibility', 'location', - 'screen' + 'screen', ] const statuses = ['not determined', 'denied', 'authorized', 'restricted'] for (const type of types) { - const status = getAuthStatus(type) + const status = permissions.getAuthStatus(type) expect(statuses).to.contain(status) } }) @@ -38,8 +40,33 @@ describe('node-mac-permissions', () => { describe('askForFoldersAccess()', () => { it('should throw on invalid types', () => { expect(() => { - askForFoldersAccess('bad-type') + permissions.askForFoldersAccess('bad-type') }).to.throw(/bad-type is not a valid protected folder/) }) }) + + describe('conditional binding', () => { + it.ifNotMac('always return undefined for non-mac OS', async () => { + const asyncModuleExports = [ + 'askForCalendarAccess', + 'askForContactsAccess', + 'askForFullDiskAccess', + 'askForRemindersAccess', + 'askForCameraAccess', + 'askForMicrophoneAccess', + 'askForPhotosAccess', + 'askForSpeechRecognitionAccess', + 'askForScreenCaptureAccess', + 'askForAccessibilityAccess', + ] + + for (const func of asyncModuleExports) { + const auth = await permissions[func]() + expect(auth).to.be.undefined + } + + expect(permissions.getAuthStatus('contacts')).to.be.undefined + expect(permissions.askForFoldersAccess('desktop')).to.be.undefined + }) + }) })