@msout/microsoft-webauth 0.0.5 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/npm-publish.yml +25 -0
- package/LICENSE +1 -1
- package/README.md +7 -1
- package/jest.config.js +12 -0
- package/package.json +2 -2
- package/src/auth.js +6 -1
- package/src/config.js +5 -0
- package/src/index.js +5 -0
- package/.qwen/settings.json +0 -38
- package/test/auth.test.js +0 -134
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
name: Publish Package
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
id-token: write # Required for OIDC
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
publish:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v6
|
|
17
|
+
|
|
18
|
+
- uses: actions/setup-node@v6
|
|
19
|
+
with:
|
|
20
|
+
node-version: '24'
|
|
21
|
+
package-manager-cache: false # never use caching in release builds
|
|
22
|
+
- run: npm ci
|
|
23
|
+
- run: npm run build --if-present
|
|
24
|
+
- run: npm test
|
|
25
|
+
- run: npm publish --access public --provenance
|
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,18 +1,24 @@
|
|
|
1
1
|
# microsoft-webauth
|
|
2
2
|
|
|
3
3
|
A tool to authenticate against microsoft online (live or professionnal tenants)
|
|
4
|
+
We do not rely on GraphAPI.
|
|
4
5
|
e.g:
|
|
5
6
|
- https://onenote.cloud.microsoft/notebooks
|
|
6
7
|
- https://outlook.live.com/mail/
|
|
7
8
|
- and by extension https://login.microsoft.com
|
|
8
9
|
|
|
9
|
-
Microsoft web authentication via Playwright — extracted from [MSOneNote Exporter](https://github.com/
|
|
10
|
+
Microsoft web authentication via Playwright — extracted from [MSOneNote Exporter](https://github.com/enoola/Microsoft-OneNote-Exporter).
|
|
11
|
+
I did extract it realising it might be useful out of the box for other projects.
|
|
12
|
+
And it will make it easier to maintain as far as I see it.
|
|
10
13
|
|
|
11
14
|
This is a standalone CLI tool for authenticating with Microsoft accounts using Playwright. It handles:
|
|
15
|
+
- NO GraphAPI
|
|
12
16
|
- Automated login with email/password
|
|
13
17
|
- Manual login in browser
|
|
14
18
|
- MFA/2FA support (OTC codes, number matching)
|
|
15
19
|
- Session persistence
|
|
20
|
+
|
|
21
|
+
|
|
16
22
|
## Available on npmjs
|
|
17
23
|
|
|
18
24
|
You can find this package here: https://www.npmjs.com/package/@msout/microsoft-webauth
|
package/jest.config.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Jest configuration.
|
|
3
|
+
* @author phptr,enoola,msout
|
|
4
|
+
* @copyright 2026 phptr,enoola,msout
|
|
5
|
+
*/
|
|
6
|
+
module.exports = {
|
|
7
|
+
testEnvironment: 'node',
|
|
8
|
+
testPathIgnorePatterns: ['/node_modules/', '/dist/'],
|
|
9
|
+
collectCoverageFrom: ['src/**/*.js'],
|
|
10
|
+
coverageDirectory: 'coverage',
|
|
11
|
+
verbose: true
|
|
12
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@msout/microsoft-webauth",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"description": "Microsoft web authentication module, using playwright to automate the login process and retrieve cookies for authenticated sessions.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"javascript"
|
|
23
23
|
],
|
|
24
24
|
"author": "msout@tuta.io",
|
|
25
|
-
"license": "
|
|
25
|
+
"license": "Apache-2.0",
|
|
26
26
|
"repository": {
|
|
27
27
|
"type": "git",
|
|
28
28
|
"url": "git+https://github.com/Ms-OneNote-Exporter/microsoft-webauth.git"
|
package/src/auth.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview This file handles user authentication logic.
|
|
3
|
+
* @author phptr,enoola,msout
|
|
4
|
+
* @copyright 2026 phptr,enoola,msout
|
|
5
|
+
*/
|
|
1
6
|
const { chromium } = require('playwright');
|
|
2
7
|
const fs = require('fs-extra');
|
|
3
8
|
const logger = require('./utils/logger');
|
|
@@ -486,7 +491,7 @@ async function login(credentials = {}) {
|
|
|
486
491
|
} catch (e) {
|
|
487
492
|
logger.debug(`Post-password verification handling skipped or failed: ${e.message}`);
|
|
488
493
|
}
|
|
489
|
-
|
|
494
|
+
|
|
490
495
|
// 2.7. Handle "Help protect your account" interrupt screen
|
|
491
496
|
try {
|
|
492
497
|
const interruptPrompt = page.getByText(/Help protect your account/i).first();
|
package/src/config.js
CHANGED
package/src/index.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Main CLI interface to handle authentication commands.
|
|
4
|
+
* @author phptr,enoola,msout
|
|
5
|
+
* @copyright 2026 phptr,enoola,msout
|
|
6
|
+
*/
|
|
2
7
|
const { program } = require('commander');
|
|
3
8
|
const logger = require('./utils/logger');
|
|
4
9
|
const { login, checkAuth, getAuthMeta, logout } = require('./auth');
|
package/.qwen/settings.json
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"permissions": {
|
|
3
|
-
"allow": [
|
|
4
|
-
"Bash(git add *)",
|
|
5
|
-
"Bash(git commit *)",
|
|
6
|
-
"Bash(git push)",
|
|
7
|
-
"Bash(cat)",
|
|
8
|
-
"Bash(let *)",
|
|
9
|
-
"Bash(beforeeach)",
|
|
10
|
-
"Bash(jest.clearallmocks)",
|
|
11
|
-
"Bash(fs.removesync)",
|
|
12
|
-
"Bash(config *)",
|
|
13
|
-
"Bash('../src/config')",
|
|
14
|
-
"Bash(auth *)",
|
|
15
|
-
"Bash('../src/auth')",
|
|
16
|
-
"Bash(})",
|
|
17
|
-
"Bash(expect)",
|
|
18
|
-
"Bash(.tobe)",
|
|
19
|
-
"Bash(eof)",
|
|
20
|
-
"Bash(npm test)",
|
|
21
|
-
"Bash(head *)",
|
|
22
|
-
"Bash(import *)",
|
|
23
|
-
"Bash(with)",
|
|
24
|
-
"Bash(as *)",
|
|
25
|
-
"Bash(content *)",
|
|
26
|
-
"Bash(old_test *)",
|
|
27
|
-
"Bash(new_test *)",
|
|
28
|
-
"Bash(const *)",
|
|
29
|
-
"Bash('https://mock.test/nonexistent')",
|
|
30
|
-
"Bash(// *)",
|
|
31
|
-
"Bash(conservative *)",
|
|
32
|
-
"Bash(}, *)",
|
|
33
|
-
"Bash('''\n\ncontent = content.replace(old_test, new_test)\n\nwith open('/users/enola/workspace-msout/microsoft-webauth-playwright-js/test/auth.test.js', 'w)",
|
|
34
|
-
"Bash(node *)"
|
|
35
|
-
]
|
|
36
|
-
},
|
|
37
|
-
"$version": 4
|
|
38
|
-
}
|
package/test/auth.test.js
DELETED
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const fs = require('fs-extra');
|
|
3
|
-
|
|
4
|
-
// Mock the modules before requiring auth
|
|
5
|
-
jest.mock('../src/config', () => ({
|
|
6
|
-
AUTH_FILE: '/tmp/test-auth.json',
|
|
7
|
-
ONENOTE_URL: 'https://www.onenote.com/notebooks',
|
|
8
|
-
OUTLOOK_URL: 'https://outlook.cloud.microsoft/mail/',
|
|
9
|
-
USER_DATA_DIR: '/tmp'
|
|
10
|
-
}));
|
|
11
|
-
|
|
12
|
-
jest.mock('../src/utils/logger', () => ({
|
|
13
|
-
info: jest.fn(),
|
|
14
|
-
warn: jest.fn(),
|
|
15
|
-
error: jest.fn(),
|
|
16
|
-
success: jest.fn(),
|
|
17
|
-
debug: jest.fn(),
|
|
18
|
-
step: jest.fn(),
|
|
19
|
-
getDumpDir: async () => '/tmp/dumps',
|
|
20
|
-
getDumpDisplayPath: () => 'logs/dumps/test'
|
|
21
|
-
}));
|
|
22
|
-
|
|
23
|
-
describe('Auth Module', () => {
|
|
24
|
-
let auth;
|
|
25
|
-
let config;
|
|
26
|
-
|
|
27
|
-
beforeEach(() => {
|
|
28
|
-
jest.clearAllMocks();
|
|
29
|
-
// Clean up test files before each test
|
|
30
|
-
fs.removeSync('/tmp/test-auth.json');
|
|
31
|
-
fs.removeSync('/tmp/test-auth-meta.json');
|
|
32
|
-
|
|
33
|
-
// Re-import after mocks are set up
|
|
34
|
-
config = require('../src/config');
|
|
35
|
-
auth = require('../src/auth');
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
afterAll(async () => {
|
|
39
|
-
// Clean up after all tests
|
|
40
|
-
fs.removeSync('/tmp/test-auth.json');
|
|
41
|
-
fs.removeSync('/tmp/test-auth-meta.json');
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
describe('getAuthMeta', () => {
|
|
45
|
-
it('should return null when no auth meta file exists', async () => {
|
|
46
|
-
const { getAuthMeta } = require('../src/auth');
|
|
47
|
-
const meta = await getAuthMeta();
|
|
48
|
-
expect(meta).toBeNull();
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('should return metadata when auth meta file exists', async () => {
|
|
52
|
-
// Create a test meta file
|
|
53
|
-
await fs.writeJson('/tmp/test-auth-meta.json', {
|
|
54
|
-
email: 'test@example.com',
|
|
55
|
-
loginTime: new Date().toISOString()
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
const { getAuthMeta } = require('../src/auth');
|
|
59
|
-
const meta = await getAuthMeta();
|
|
60
|
-
|
|
61
|
-
expect(meta).toBeDefined();
|
|
62
|
-
expect(meta.email).toBe('test@example.com');
|
|
63
|
-
expect(meta.loginTime).toBeDefined();
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
describe('logout', () => {
|
|
68
|
-
it('should remove auth files', async () => {
|
|
69
|
-
// Create test files
|
|
70
|
-
await fs.writeJson('/tmp/test-auth.json', { test: true });
|
|
71
|
-
await fs.writeJson('/tmp/test-auth-meta.json', { email: 'test@example.com' });
|
|
72
|
-
|
|
73
|
-
const { logout } = require('../src/auth');
|
|
74
|
-
await logout();
|
|
75
|
-
|
|
76
|
-
expect(await fs.pathExists('/tmp/test-auth.json')).toBe(false);
|
|
77
|
-
expect(await fs.pathExists('/tmp/test-auth-meta.json')).toBe(false);
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
describe('checkAuth', () => {
|
|
82
|
-
it('should return false when no auth file exists', async () => {
|
|
83
|
-
const { checkAuth } = require('../src/auth');
|
|
84
|
-
const isAuth = await checkAuth();
|
|
85
|
-
expect(isAuth).toBe(false);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it('should handle network errors gracefully', async () => {
|
|
89
|
-
// Create a dummy auth file
|
|
90
|
-
await fs.writeJson('/tmp/test-auth.json', { test: true });
|
|
91
|
-
|
|
92
|
-
const { checkAuth } = require('../src/auth');
|
|
93
|
-
// Use mock URL that won't actually connect
|
|
94
|
-
const isAuth = await checkAuth('https://mock.test/nonexistent');
|
|
95
|
-
|
|
96
|
-
// Should return true on error (conservative approach)
|
|
97
|
-
expect(isAuth).toBe(true);
|
|
98
|
-
}, 10000);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
describe('getAuthenticatedContext', () => {
|
|
102
|
-
it('should throw error when no auth file exists', async () => {
|
|
103
|
-
const { getAuthenticatedContext } = require('../src/auth');
|
|
104
|
-
|
|
105
|
-
await expect(getAuthenticatedContext(null)).rejects.toThrow(
|
|
106
|
-
'No authentication state found. Please run "login" command first.'
|
|
107
|
-
);
|
|
108
|
-
});
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
describe('config', () => {
|
|
113
|
-
let config;
|
|
114
|
-
|
|
115
|
-
beforeEach(() => {
|
|
116
|
-
jest.clearAllMocks();
|
|
117
|
-
fs.removeSync('/tmp/test-auth.json');
|
|
118
|
-
fs.removeSync('/tmp/test-auth-meta.json');
|
|
119
|
-
config = require('../src/config');
|
|
120
|
-
auth = require('../src/auth');
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it('should export AUTH_FILE', () => {
|
|
124
|
-
expect(config.AUTH_FILE).toBe('/tmp/test-auth.json');
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it('should export ONENOTE_URL', () => {
|
|
128
|
-
expect(config.ONENOTE_URL).toBe('https://www.onenote.com/notebooks');
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it('should export OUTLOOK_URL', () => {
|
|
132
|
-
expect(config.OUTLOOK_URL).toBe('https://outlook.cloud.microsoft/mail/');
|
|
133
|
-
});
|
|
134
|
-
});
|