@tldraw/editor 3.16.0-next.fe14f1b4181f → 4.0.1
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/dist-cjs/index.d.ts +91 -111
- package/dist-cjs/index.js +3 -5
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +1 -7
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +11 -1
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/config/TLUserPreferences.js +15 -4
- package/dist-cjs/lib/config/TLUserPreferences.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +58 -114
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/notVisibleShapes.js +4 -0
- package/dist-cjs/lib/editor/derivations/notVisibleShapes.js.map +2 -2
- package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js +4 -2
- package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +11 -6
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js +10 -0
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/types/misc-types.js.map +1 -1
- package/dist-cjs/lib/hooks/useCanvasEvents.js +19 -16
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useDocumentEvents.js +5 -5
- package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js +1 -2
- package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useGestureEvents.js +1 -1
- package/dist-cjs/lib/hooks/useGestureEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useHandleEvents.js +6 -6
- package/dist-cjs/lib/hooks/useHandleEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js +4 -1
- package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useSelectionEvents.js +8 -8
- package/dist-cjs/lib/hooks/useSelectionEvents.js.map +2 -2
- package/dist-cjs/lib/license/LicenseManager.js +147 -59
- package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
- package/dist-cjs/lib/license/LicenseProvider.js +39 -1
- package/dist-cjs/lib/license/LicenseProvider.js.map +2 -2
- package/dist-cjs/lib/license/Watermark.js +144 -75
- package/dist-cjs/lib/license/Watermark.js.map +3 -3
- package/dist-cjs/lib/license/useLicenseManagerState.js.map +2 -2
- package/dist-cjs/lib/primitives/Vec.js +0 -4
- package/dist-cjs/lib/primitives/Vec.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js +50 -20
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Group2d.js +8 -1
- package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
- package/dist-cjs/lib/utils/dom.js.map +2 -2
- package/dist-cjs/lib/utils/getPointerInfo.js +2 -3
- package/dist-cjs/lib/utils/getPointerInfo.js.map +2 -2
- package/dist-cjs/lib/utils/reparenting.js +7 -36
- package/dist-cjs/lib/utils/reparenting.js.map +3 -3
- package/dist-cjs/version.js +4 -4
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +91 -111
- package/dist-esm/index.mjs +3 -5
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +1 -7
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +11 -1
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/config/TLUserPreferences.mjs +15 -4
- package/dist-esm/lib/config/TLUserPreferences.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +58 -114
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs +4 -0
- package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs +4 -2
- package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +11 -6
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +10 -0
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +20 -22
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useDocumentEvents.mjs +6 -6
- package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs +1 -2
- package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useGestureEvents.mjs +2 -2
- package/dist-esm/lib/hooks/useGestureEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useHandleEvents.mjs +6 -6
- package/dist-esm/lib/hooks/useHandleEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs +4 -1
- package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useSelectionEvents.mjs +9 -14
- package/dist-esm/lib/hooks/useSelectionEvents.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseManager.mjs +148 -60
- package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseProvider.mjs +39 -2
- package/dist-esm/lib/license/LicenseProvider.mjs.map +2 -2
- package/dist-esm/lib/license/Watermark.mjs +145 -76
- package/dist-esm/lib/license/Watermark.mjs.map +3 -3
- package/dist-esm/lib/license/useLicenseManagerState.mjs.map +2 -2
- package/dist-esm/lib/primitives/Vec.mjs +0 -4
- package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +53 -21
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Group2d.mjs +8 -1
- package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
- package/dist-esm/lib/utils/dom.mjs.map +2 -2
- package/dist-esm/lib/utils/getPointerInfo.mjs +2 -3
- package/dist-esm/lib/utils/getPointerInfo.mjs.map +2 -2
- package/dist-esm/lib/utils/reparenting.mjs +8 -41
- package/dist-esm/lib/utils/reparenting.mjs.map +2 -2
- package/dist-esm/version.mjs +4 -4
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +8 -3
- package/package.json +7 -7
- package/src/index.ts +2 -10
- package/src/lib/TldrawEditor.tsx +1 -15
- package/src/lib/components/default-components/DefaultCanvas.tsx +7 -1
- package/src/lib/config/TLUserPreferences.ts +16 -3
- package/src/lib/editor/Editor.test.ts +90 -0
- package/src/lib/editor/Editor.ts +77 -151
- package/src/lib/editor/derivations/notVisibleShapes.ts +6 -0
- package/src/lib/editor/managers/FocusManager/FocusManager.ts +6 -2
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +30 -8
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +10 -3
- package/src/lib/editor/shapes/ShapeUtil.ts +32 -0
- package/src/lib/editor/types/misc-types.ts +0 -6
- package/src/lib/hooks/useCanvasEvents.ts +20 -20
- package/src/lib/hooks/useDocumentEvents.ts +6 -6
- package/src/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.ts +1 -1
- package/src/lib/hooks/useGestureEvents.ts +2 -2
- package/src/lib/hooks/useHandleEvents.ts +6 -6
- package/src/lib/hooks/usePassThroughMouseOverEvents.ts +4 -1
- package/src/lib/hooks/useSelectionEvents.ts +9 -14
- package/src/lib/license/LicenseManager.test.ts +780 -377
- package/src/lib/license/LicenseManager.ts +207 -70
- package/src/lib/license/LicenseProvider.tsx +74 -2
- package/src/lib/license/Watermark.tsx +152 -77
- package/src/lib/license/useLicenseManagerState.ts +2 -2
- package/src/lib/primitives/Vec.ts +0 -5
- package/src/lib/primitives/geometry/Geometry2d.test.ts +420 -0
- package/src/lib/primitives/geometry/Geometry2d.ts +78 -21
- package/src/lib/primitives/geometry/Group2d.ts +10 -1
- package/src/lib/test/InFrontOfTheCanvas.test.tsx +187 -0
- package/src/lib/utils/dom.test.ts +103 -0
- package/src/lib/utils/dom.ts +8 -1
- package/src/lib/utils/getPointerInfo.ts +3 -2
- package/src/lib/utils/reparenting.ts +10 -70
- package/src/version.ts +4 -4
|
@@ -4,7 +4,7 @@ import { publishDates } from '../../version'
|
|
|
4
4
|
import { str2ab } from '../utils/licensing'
|
|
5
5
|
import {
|
|
6
6
|
FLAGS,
|
|
7
|
-
|
|
7
|
+
getLicenseState,
|
|
8
8
|
LicenseManager,
|
|
9
9
|
PROPERTIES,
|
|
10
10
|
ValidLicenseKeyResult,
|
|
@@ -36,13 +36,15 @@ describe('LicenseManager', () => {
|
|
|
36
36
|
let licenseManager: LicenseManager
|
|
37
37
|
|
|
38
38
|
beforeAll(() => {
|
|
39
|
+
process.env.NODE_ENV = 'production'
|
|
39
40
|
return new Promise((resolve) => {
|
|
40
41
|
generateKeyPair().then((kp) => {
|
|
41
42
|
keyPair = kp
|
|
42
|
-
licenseManager = new LicenseManager('', keyPair.publicKey
|
|
43
|
+
licenseManager = new LicenseManager('', keyPair.publicKey)
|
|
43
44
|
resolve(void 0)
|
|
44
45
|
})
|
|
45
46
|
})
|
|
47
|
+
process.env.NODE_ENV = 'test'
|
|
46
48
|
})
|
|
47
49
|
|
|
48
50
|
beforeEach(() => {
|
|
@@ -52,337 +54,558 @@ describe('LicenseManager', () => {
|
|
|
52
54
|
window.location = new URL('https://www.example.com')
|
|
53
55
|
})
|
|
54
56
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
describe('Basic license validation', () => {
|
|
58
|
+
it('Fails if no key provided', async () => {
|
|
59
|
+
const result = await licenseManager.getLicenseFromKey('')
|
|
60
|
+
expect(result).toMatchObject({ isLicenseParseable: false, reason: 'no-key-provided' })
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('Signals that it is development mode when localhost', async () => {
|
|
64
|
+
const schemes = ['http', 'https']
|
|
65
|
+
for (const scheme of schemes) {
|
|
66
|
+
// @ts-ignore
|
|
67
|
+
delete window.location
|
|
68
|
+
// @ts-ignore
|
|
69
|
+
window.location = new URL(`${scheme}://localhost:3000`)
|
|
70
|
+
|
|
71
|
+
const testEnvLicenseManager = new LicenseManager('', keyPair.publicKey)
|
|
72
|
+
const licenseKey = await generateLicenseKey(STANDARD_LICENSE_INFO, keyPair)
|
|
73
|
+
const result = await testEnvLicenseManager.getLicenseFromKey(licenseKey)
|
|
74
|
+
expect(result).toMatchObject({
|
|
75
|
+
isLicenseParseable: true,
|
|
76
|
+
isDomainValid: false,
|
|
77
|
+
isDevelopment: true,
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
})
|
|
59
81
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
for (const scheme of schemes) {
|
|
82
|
+
it('Signals that it is development mode when NODE_ENV is not production', async () => {
|
|
83
|
+
process.env.NODE_ENV = 'development'
|
|
63
84
|
// @ts-ignore
|
|
64
85
|
delete window.location
|
|
65
86
|
// @ts-ignore
|
|
66
|
-
window.location = new URL(
|
|
87
|
+
window.location = new URL(`https://www.example.com`)
|
|
67
88
|
|
|
68
|
-
const testEnvLicenseManager = new LicenseManager('', keyPair.publicKey
|
|
89
|
+
const testEnvLicenseManager = new LicenseManager('', keyPair.publicKey)
|
|
69
90
|
const licenseKey = await generateLicenseKey(STANDARD_LICENSE_INFO, keyPair)
|
|
70
91
|
const result = await testEnvLicenseManager.getLicenseFromKey(licenseKey)
|
|
71
92
|
expect(result).toMatchObject({
|
|
72
93
|
isLicenseParseable: true,
|
|
73
|
-
isDomainValid:
|
|
94
|
+
isDomainValid: true,
|
|
74
95
|
isDevelopment: true,
|
|
75
96
|
})
|
|
76
|
-
|
|
77
|
-
|
|
97
|
+
const licenseState = testEnvLicenseManager.state.get()
|
|
98
|
+
expect(licenseState).toBe('unlicensed')
|
|
99
|
+
process.env.NODE_ENV = 'test'
|
|
100
|
+
})
|
|
78
101
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
102
|
+
it('Signals that it is development mode when NODE_ENV is "test"', async () => {
|
|
103
|
+
process.env.NODE_ENV = 'test'
|
|
104
|
+
// @ts-ignore
|
|
105
|
+
delete window.location
|
|
106
|
+
// @ts-ignore
|
|
107
|
+
window.location = new URL(`https://www.example.com`)
|
|
85
108
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
109
|
+
const testEnvLicenseManager = new LicenseManager('', keyPair.publicKey)
|
|
110
|
+
const licenseKey = await generateLicenseKey(STANDARD_LICENSE_INFO, keyPair)
|
|
111
|
+
const result = await testEnvLicenseManager.getLicenseFromKey(licenseKey)
|
|
112
|
+
expect(result).toMatchObject({
|
|
113
|
+
isLicenseParseable: true,
|
|
114
|
+
isDomainValid: true,
|
|
115
|
+
isDevelopment: true,
|
|
116
|
+
})
|
|
117
|
+
const licenseState = testEnvLicenseManager.state.get()
|
|
118
|
+
expect(licenseState).toBe('unlicensed')
|
|
119
|
+
process.env.NODE_ENV = 'test'
|
|
120
|
+
})
|
|
92
121
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
122
|
+
it('Signals that it is not development mode when NODE_ENV is production', async () => {
|
|
123
|
+
process.env.NODE_ENV = 'production'
|
|
124
|
+
// @ts-ignore
|
|
125
|
+
delete window.location
|
|
126
|
+
// @ts-ignore
|
|
127
|
+
window.location = new URL(`https://www.example.com`)
|
|
98
128
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
isAnnualLicense: true,
|
|
112
|
-
isAnnualLicenseExpired: false,
|
|
113
|
-
isPerpetualLicense: false,
|
|
114
|
-
isPerpetualLicenseExpired: false,
|
|
115
|
-
isInternalLicense: false,
|
|
116
|
-
} as ValidLicenseKeyResult)
|
|
117
|
-
})
|
|
129
|
+
const testEnvLicenseManager = new LicenseManager('', keyPair.publicKey)
|
|
130
|
+
const licenseKey = await generateLicenseKey(STANDARD_LICENSE_INFO, keyPair)
|
|
131
|
+
const result = await testEnvLicenseManager.getLicenseFromKey(licenseKey)
|
|
132
|
+
expect(result).toMatchObject({
|
|
133
|
+
isLicenseParseable: true,
|
|
134
|
+
isDomainValid: true,
|
|
135
|
+
isDevelopment: false,
|
|
136
|
+
})
|
|
137
|
+
const licenseState = testEnvLicenseManager.state.get()
|
|
138
|
+
expect(licenseState).toBe('unlicensed-production')
|
|
139
|
+
process.env.NODE_ENV = 'test'
|
|
140
|
+
})
|
|
118
141
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
expiredLicenseKey
|
|
126
|
-
)) as ValidLicenseKeyResult
|
|
127
|
-
expect(result.isAnnualLicenseExpired).toBe(true)
|
|
128
|
-
})
|
|
142
|
+
it('Cleanses out valid keys that accidentally have zero-width characters or newlines', async () => {
|
|
143
|
+
const cleanLicenseKey = await generateLicenseKey(STANDARD_LICENSE_INFO, keyPair)
|
|
144
|
+
const dirtyLicenseKey = cleanLicenseKey + '\u200B\u200D\uFEFF\n\r'
|
|
145
|
+
const result = await licenseManager.getLicenseFromKey(dirtyLicenseKey)
|
|
146
|
+
expect(result.isLicenseParseable).toBe(true)
|
|
147
|
+
})
|
|
129
148
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
)
|
|
138
|
-
const result = (await licenseManager.getLicenseFromKey(
|
|
139
|
-
almostExpiredLicenseKey
|
|
140
|
-
)) as ValidLicenseKeyResult
|
|
141
|
-
expect(result.isAnnualLicenseExpired).toBe(false)
|
|
142
|
-
})
|
|
149
|
+
it('Fails if garbage key provided', async () => {
|
|
150
|
+
process.env.NODE_ENV = 'production'
|
|
151
|
+
const badPublicKeyLicenseManager = new LicenseManager('', 'badpublickey')
|
|
152
|
+
const invalidLicenseKey = await generateLicenseKey(STANDARD_LICENSE_INFO, keyPair)
|
|
153
|
+
const result = await badPublicKeyLicenseManager.getLicenseFromKey(invalidLicenseKey)
|
|
154
|
+
expect(result).toMatchObject({ isLicenseParseable: false, reason: 'invalid-license-key' })
|
|
155
|
+
process.env.NODE_ENV = 'test'
|
|
156
|
+
})
|
|
143
157
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
majorDate.getMonth(),
|
|
150
|
-
majorDate.getDate() + 100
|
|
151
|
-
)
|
|
152
|
-
const perpetualLicenseInfo = ['id', ['www.example.com'], FLAGS.PERPETUAL_LICENSE, expiryDate]
|
|
153
|
-
const almostExpiredLicenseKey = await generateLicenseKey(
|
|
154
|
-
JSON.stringify(perpetualLicenseInfo),
|
|
155
|
-
keyPair
|
|
156
|
-
)
|
|
157
|
-
const result = (await licenseManager.getLicenseFromKey(
|
|
158
|
-
almostExpiredLicenseKey
|
|
159
|
-
)) as ValidLicenseKeyResult
|
|
160
|
-
expect(result.isPerpetualLicense).toBe(true)
|
|
161
|
-
expect(result.isPerpetualLicenseExpired).toBe(false)
|
|
162
|
-
})
|
|
158
|
+
it('Fails if non-JSON parseable message is provided', async () => {
|
|
159
|
+
const invalidMessage = await generateLicenseKey('asdfsad', keyPair)
|
|
160
|
+
const result = await licenseManager.getLicenseFromKey(invalidMessage)
|
|
161
|
+
expect(result).toMatchObject({ isLicenseParseable: false, reason: 'invalid-license-key' })
|
|
162
|
+
})
|
|
163
163
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
164
|
+
it('Succeeds if valid key provided', async () => {
|
|
165
|
+
const licenseKey = await generateLicenseKey(STANDARD_LICENSE_INFO, keyPair)
|
|
166
|
+
const result = await licenseManager.getLicenseFromKey(licenseKey)
|
|
167
|
+
expect(result).toMatchObject({
|
|
168
|
+
isLicenseParseable: true,
|
|
169
|
+
license: {
|
|
170
|
+
id: 'id',
|
|
171
|
+
hosts: ['www.example.com'],
|
|
172
|
+
flags: FLAGS.ANNUAL_LICENSE,
|
|
173
|
+
expiryDate,
|
|
174
|
+
},
|
|
175
|
+
isDomainValid: true,
|
|
176
|
+
isAnnualLicense: true,
|
|
177
|
+
isAnnualLicenseExpired: false,
|
|
178
|
+
isPerpetualLicense: false,
|
|
179
|
+
isPerpetualLicenseExpired: false,
|
|
180
|
+
isInternalLicense: false,
|
|
181
|
+
isEvaluationLicense: false,
|
|
182
|
+
isEvaluationLicenseExpired: false,
|
|
183
|
+
daysSinceExpiry: 0,
|
|
184
|
+
} as ValidLicenseKeyResult)
|
|
185
|
+
})
|
|
181
186
|
})
|
|
182
187
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
+
describe('Domain validation', () => {
|
|
189
|
+
it('Fails with invalid host', async () => {
|
|
190
|
+
// @ts-ignore
|
|
191
|
+
delete window.location
|
|
192
|
+
// @ts-ignore
|
|
193
|
+
window.location = new URL('https://www.foo.com')
|
|
188
194
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
+
const expiredLicenseKey = await generateLicenseKey(STANDARD_LICENSE_INFO, keyPair)
|
|
196
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
197
|
+
expiredLicenseKey
|
|
198
|
+
)) as ValidLicenseKeyResult
|
|
199
|
+
expect(result.isDomainValid).toBe(false)
|
|
200
|
+
})
|
|
195
201
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
202
|
+
it('Succeeds if hosts is equal to only "*"', async () => {
|
|
203
|
+
// @ts-ignore
|
|
204
|
+
delete window.location
|
|
205
|
+
// @ts-ignore
|
|
206
|
+
window.location = new URL('https://www.foo.com')
|
|
207
|
+
|
|
208
|
+
const permissiveHostsInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
209
|
+
permissiveHostsInfo[PROPERTIES.HOSTS] = ['*']
|
|
210
|
+
const permissiveLicenseKey = await generateLicenseKey(
|
|
211
|
+
JSON.stringify(permissiveHostsInfo),
|
|
212
|
+
keyPair
|
|
213
|
+
)
|
|
214
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
215
|
+
permissiveLicenseKey
|
|
216
|
+
)) as ValidLicenseKeyResult
|
|
217
|
+
expect(result.isDomainValid).toBe(true)
|
|
218
|
+
})
|
|
213
219
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
220
|
+
it('Succeeds if has an apex domain specified', async () => {
|
|
221
|
+
// @ts-ignore
|
|
222
|
+
delete window.location
|
|
223
|
+
// @ts-ignore
|
|
224
|
+
window.location = new URL('https://www.example.com')
|
|
225
|
+
|
|
226
|
+
const permissiveHostsInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
227
|
+
permissiveHostsInfo[PROPERTIES.HOSTS] = ['example.com']
|
|
228
|
+
const permissiveLicenseKey = await generateLicenseKey(
|
|
229
|
+
JSON.stringify(permissiveHostsInfo),
|
|
230
|
+
keyPair
|
|
231
|
+
)
|
|
232
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
233
|
+
permissiveLicenseKey
|
|
234
|
+
)) as ValidLicenseKeyResult
|
|
235
|
+
expect(result.isDomainValid).toBe(true)
|
|
236
|
+
})
|
|
219
237
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
238
|
+
it('Succeeds if has an www domain specified, but at the apex domain', async () => {
|
|
239
|
+
// @ts-ignore
|
|
240
|
+
delete window.location
|
|
241
|
+
// @ts-ignore
|
|
242
|
+
window.location = new URL('https://example.com')
|
|
243
|
+
|
|
244
|
+
const permissiveHostsInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
245
|
+
permissiveHostsInfo[PROPERTIES.HOSTS] = ['www.example.com']
|
|
246
|
+
const permissiveLicenseKey = await generateLicenseKey(
|
|
247
|
+
JSON.stringify(permissiveHostsInfo),
|
|
248
|
+
keyPair
|
|
249
|
+
)
|
|
250
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
251
|
+
permissiveLicenseKey
|
|
252
|
+
)) as ValidLicenseKeyResult
|
|
253
|
+
expect(result.isDomainValid).toBe(true)
|
|
254
|
+
})
|
|
231
255
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
256
|
+
it('Succeeds if has a subdomain wildcard', async () => {
|
|
257
|
+
// @ts-ignore
|
|
258
|
+
delete window.location
|
|
259
|
+
// @ts-ignore
|
|
260
|
+
window.location = new URL('https://sub.example.com')
|
|
261
|
+
|
|
262
|
+
const permissiveHostsInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
263
|
+
permissiveHostsInfo[PROPERTIES.HOSTS] = ['*.example.com']
|
|
264
|
+
const permissiveLicenseKey = await generateLicenseKey(
|
|
265
|
+
JSON.stringify(permissiveHostsInfo),
|
|
266
|
+
keyPair
|
|
267
|
+
)
|
|
268
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
269
|
+
permissiveLicenseKey
|
|
270
|
+
)) as ValidLicenseKeyResult
|
|
271
|
+
expect(result.isDomainValid).toBe(true)
|
|
272
|
+
})
|
|
249
273
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
274
|
+
it('Succeeds if has a sub-subdomain wildcard', async () => {
|
|
275
|
+
// @ts-ignore
|
|
276
|
+
delete window.location
|
|
277
|
+
// @ts-ignore
|
|
278
|
+
window.location = new URL('https://pr-2408.sub.example.com')
|
|
279
|
+
|
|
280
|
+
const permissiveHostsInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
281
|
+
permissiveHostsInfo[PROPERTIES.HOSTS] = ['*.example.com']
|
|
282
|
+
const permissiveLicenseKey = await generateLicenseKey(
|
|
283
|
+
JSON.stringify(permissiveHostsInfo),
|
|
284
|
+
keyPair
|
|
285
|
+
)
|
|
286
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
287
|
+
permissiveLicenseKey
|
|
288
|
+
)) as ValidLicenseKeyResult
|
|
289
|
+
expect(result.isDomainValid).toBe(true)
|
|
290
|
+
})
|
|
267
291
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
292
|
+
it('Succeeds if has a subdomain wildcard but on an apex domain', async () => {
|
|
293
|
+
// @ts-ignore
|
|
294
|
+
delete window.location
|
|
295
|
+
// @ts-ignore
|
|
296
|
+
window.location = new URL('https://example.com')
|
|
297
|
+
|
|
298
|
+
const permissiveHostsInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
299
|
+
permissiveHostsInfo[PROPERTIES.HOSTS] = ['*.example.com']
|
|
300
|
+
const permissiveLicenseKey = await generateLicenseKey(
|
|
301
|
+
JSON.stringify(permissiveHostsInfo),
|
|
302
|
+
keyPair
|
|
303
|
+
)
|
|
304
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
305
|
+
permissiveLicenseKey
|
|
306
|
+
)) as ValidLicenseKeyResult
|
|
307
|
+
expect(result.isDomainValid).toBe(true)
|
|
308
|
+
})
|
|
285
309
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
310
|
+
it('Fails if has a subdomain wildcard isnt for the same base domain', async () => {
|
|
311
|
+
// @ts-ignore
|
|
312
|
+
delete window.location
|
|
313
|
+
// @ts-ignore
|
|
314
|
+
window.location = new URL('https://sub.example.com')
|
|
315
|
+
|
|
316
|
+
const permissiveHostsInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
317
|
+
permissiveHostsInfo[PROPERTIES.HOSTS] = ['*.foo.com']
|
|
318
|
+
const permissiveLicenseKey = await generateLicenseKey(
|
|
319
|
+
JSON.stringify(permissiveHostsInfo),
|
|
320
|
+
keyPair
|
|
321
|
+
)
|
|
322
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
323
|
+
permissiveLicenseKey
|
|
324
|
+
)) as ValidLicenseKeyResult
|
|
325
|
+
expect(result.isDomainValid).toBe(false)
|
|
326
|
+
})
|
|
303
327
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
328
|
+
it('Succeeds if it is a vscode extension', async () => {
|
|
329
|
+
// @ts-ignore
|
|
330
|
+
delete window.location
|
|
331
|
+
// @ts-ignore
|
|
332
|
+
window.location = new URL(
|
|
333
|
+
'vscode-webview://1ipd8pun8ud7nd7hv9d112g7evi7m10vak9vviuvia66ou6aibp3/index.html?id=6ec2dc7a-afe9-45d9-bd71-1749f9568d28&origin=955b256f-37e1-4a72-a2f4-ad633e88239c&swVersion=4&extensionId=tldraw-org.tldraw-vscode&platform=electron&vscode-resource-base-authority=vscode-resource.vscode-cdn.net&parentOrigin=vscode-file%3A%2F%2Fvscode-app'
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
const permissiveHostsInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
337
|
+
permissiveHostsInfo[PROPERTIES.HOSTS] = ['tldraw-org.tldraw-vscode']
|
|
338
|
+
const permissiveLicenseKey = await generateLicenseKey(
|
|
339
|
+
JSON.stringify(permissiveHostsInfo),
|
|
340
|
+
keyPair
|
|
341
|
+
)
|
|
342
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
343
|
+
permissiveLicenseKey
|
|
344
|
+
)) as ValidLicenseKeyResult
|
|
345
|
+
expect(result.isDomainValid).toBe(true)
|
|
346
|
+
})
|
|
321
347
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
348
|
+
it('Fails if it is a vscode extension with the wrong id', async () => {
|
|
349
|
+
// @ts-ignore
|
|
350
|
+
delete window.location
|
|
351
|
+
// @ts-ignore
|
|
352
|
+
window.location = new URL(
|
|
353
|
+
'vscode-webview://1ipd8pun8ud7nd7hv9d112g7evi7m10vak9vviuvia66ou6aibp3/index.html?id=6ec2dc7a-afe9-45d9-bd71-1749f9568d28&origin=955b256f-37e1-4a72-a2f4-ad633e88239c&swVersion=4&extensionId=tldraw-org.tldraw-vscode&platform=electron&vscode-resource-base-authority=vscode-resource.vscode-cdn.net&parentOrigin=vscode-file%3A%2F%2Fvscode-app'
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
const permissiveHostsInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
357
|
+
permissiveHostsInfo[PROPERTIES.HOSTS] = ['blah-org.blah-vscode']
|
|
358
|
+
const permissiveLicenseKey = await generateLicenseKey(
|
|
359
|
+
JSON.stringify(permissiveHostsInfo),
|
|
360
|
+
keyPair
|
|
361
|
+
)
|
|
362
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
363
|
+
permissiveLicenseKey
|
|
364
|
+
)) as ValidLicenseKeyResult
|
|
365
|
+
expect(result.isDomainValid).toBe(false)
|
|
366
|
+
})
|
|
367
|
+
|
|
368
|
+
it('Succeeds if it is a native app', async () => {
|
|
369
|
+
// @ts-ignore
|
|
370
|
+
delete window.location
|
|
371
|
+
// @ts-ignore
|
|
372
|
+
window.location = new URL('app-bundle://app/index.html')
|
|
373
|
+
|
|
374
|
+
const nativeLicenseInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
375
|
+
nativeLicenseInfo[PROPERTIES.FLAGS] = FLAGS.NATIVE_LICENSE
|
|
376
|
+
nativeLicenseInfo[PROPERTIES.HOSTS] = ['app-bundle:']
|
|
377
|
+
const nativeLicenseKey = await generateLicenseKey(JSON.stringify(nativeLicenseInfo), keyPair)
|
|
378
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
379
|
+
nativeLicenseKey
|
|
380
|
+
)) as ValidLicenseKeyResult
|
|
381
|
+
expect(result.isDomainValid).toBe(true)
|
|
382
|
+
})
|
|
383
|
+
|
|
384
|
+
it('Succeeds if it is a native app with a wildcard', async () => {
|
|
385
|
+
// @ts-ignore
|
|
386
|
+
delete window.location
|
|
387
|
+
// @ts-ignore
|
|
388
|
+
window.location = new URL('app-bundle://unique-id-123/index.html')
|
|
389
|
+
|
|
390
|
+
const nativeLicenseInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
391
|
+
nativeLicenseInfo[PROPERTIES.FLAGS] = FLAGS.NATIVE_LICENSE
|
|
392
|
+
nativeLicenseInfo[PROPERTIES.HOSTS] = ['^app-bundle://unique-id-123.*']
|
|
393
|
+
const nativeLicenseKey = await generateLicenseKey(JSON.stringify(nativeLicenseInfo), keyPair)
|
|
394
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
395
|
+
nativeLicenseKey
|
|
396
|
+
)) as ValidLicenseKeyResult
|
|
397
|
+
expect(result.isDomainValid).toBe(true)
|
|
398
|
+
})
|
|
399
|
+
|
|
400
|
+
it('Succeeds if it is a native app with a wildcard and search param', async () => {
|
|
401
|
+
// @ts-ignore
|
|
402
|
+
delete window.location
|
|
403
|
+
// @ts-ignore
|
|
404
|
+
window.location = new URL('app-bundle://app/index.html?unique-id-123')
|
|
405
|
+
|
|
406
|
+
const nativeLicenseInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
407
|
+
nativeLicenseInfo[PROPERTIES.FLAGS] = FLAGS.NATIVE_LICENSE
|
|
408
|
+
nativeLicenseInfo[PROPERTIES.HOSTS] = ['^app-bundle://app.*unique-id-123.*']
|
|
409
|
+
const nativeLicenseKey = await generateLicenseKey(JSON.stringify(nativeLicenseInfo), keyPair)
|
|
410
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
411
|
+
nativeLicenseKey
|
|
412
|
+
)) as ValidLicenseKeyResult
|
|
413
|
+
expect(result.isDomainValid).toBe(true)
|
|
414
|
+
})
|
|
415
|
+
|
|
416
|
+
it('Fails if it is a native app with the wrong protocol', async () => {
|
|
417
|
+
// @ts-ignore
|
|
418
|
+
delete window.location
|
|
419
|
+
// @ts-ignore
|
|
420
|
+
window.location = new URL('blah-blundle://app/index.html')
|
|
421
|
+
|
|
422
|
+
const nativeLicenseInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
423
|
+
nativeLicenseInfo[PROPERTIES.FLAGS] = FLAGS.NATIVE_LICENSE
|
|
424
|
+
nativeLicenseInfo[PROPERTIES.HOSTS] = ['app-bundle:']
|
|
425
|
+
const nativeLicenseKey = await generateLicenseKey(JSON.stringify(nativeLicenseInfo), keyPair)
|
|
426
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
427
|
+
nativeLicenseKey
|
|
428
|
+
)) as ValidLicenseKeyResult
|
|
429
|
+
expect(result.isDomainValid).toBe(false)
|
|
430
|
+
})
|
|
340
431
|
})
|
|
341
432
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
433
|
+
describe('License types and flags', () => {
|
|
434
|
+
it('Checks for internal license', async () => {
|
|
435
|
+
const internalLicenseInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
436
|
+
internalLicenseInfo[PROPERTIES.FLAGS] = FLAGS.INTERNAL_LICENSE
|
|
437
|
+
const internalLicenseKey = await generateLicenseKey(
|
|
438
|
+
JSON.stringify(internalLicenseInfo),
|
|
439
|
+
keyPair
|
|
440
|
+
)
|
|
441
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
442
|
+
internalLicenseKey
|
|
443
|
+
)) as ValidLicenseKeyResult
|
|
444
|
+
expect(result.isInternalLicense).toBe(true)
|
|
445
|
+
})
|
|
446
|
+
|
|
447
|
+
it('Checks for native license', async () => {
|
|
448
|
+
const nativeLicenseInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
449
|
+
nativeLicenseInfo[PROPERTIES.FLAGS] = FLAGS.NATIVE_LICENSE
|
|
450
|
+
const nativeLicenseKey = await generateLicenseKey(JSON.stringify(nativeLicenseInfo), keyPair)
|
|
451
|
+
|
|
452
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
453
|
+
nativeLicenseKey
|
|
454
|
+
)) as ValidLicenseKeyResult
|
|
455
|
+
expect(result.isNativeLicense).toBe(true)
|
|
456
|
+
})
|
|
457
|
+
|
|
458
|
+
it('Checks for license with watermark', async () => {
|
|
459
|
+
const withWatermarkLicenseInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
460
|
+
withWatermarkLicenseInfo[PROPERTIES.FLAGS] |= FLAGS.WITH_WATERMARK
|
|
461
|
+
const withWatermarkLicenseKey = await generateLicenseKey(
|
|
462
|
+
JSON.stringify(withWatermarkLicenseInfo),
|
|
463
|
+
keyPair
|
|
464
|
+
)
|
|
465
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
466
|
+
withWatermarkLicenseKey
|
|
467
|
+
)) as ValidLicenseKeyResult
|
|
468
|
+
expect(result.isLicensedWithWatermark).toBe(true)
|
|
469
|
+
})
|
|
470
|
+
|
|
471
|
+
it('Checks for evaluation license', async () => {
|
|
472
|
+
const evaluationLicenseInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
473
|
+
evaluationLicenseInfo[PROPERTIES.FLAGS] = FLAGS.EVALUATION_LICENSE
|
|
474
|
+
const evaluationLicenseKey = await generateLicenseKey(
|
|
475
|
+
JSON.stringify(evaluationLicenseInfo),
|
|
476
|
+
keyPair
|
|
477
|
+
)
|
|
478
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
479
|
+
evaluationLicenseKey
|
|
480
|
+
)) as ValidLicenseKeyResult
|
|
481
|
+
expect(result.isEvaluationLicense).toBe(true)
|
|
482
|
+
expect(result.isEvaluationLicenseExpired).toBe(false)
|
|
483
|
+
})
|
|
484
|
+
|
|
485
|
+
it('Detects when evaluation license has expired', async () => {
|
|
486
|
+
const expiredEvaluationLicenseInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
487
|
+
expiredEvaluationLicenseInfo[PROPERTIES.FLAGS] = FLAGS.EVALUATION_LICENSE
|
|
488
|
+
const expiredDate = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1) // 1 day ago
|
|
489
|
+
expiredEvaluationLicenseInfo[PROPERTIES.EXPIRY_DATE] = expiredDate.toISOString()
|
|
490
|
+
|
|
491
|
+
const expiredEvaluationLicenseKey = await generateLicenseKey(
|
|
492
|
+
JSON.stringify(expiredEvaluationLicenseInfo),
|
|
493
|
+
keyPair
|
|
494
|
+
)
|
|
495
|
+
|
|
496
|
+
// The getLicenseFromKey should return the expired state
|
|
497
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
498
|
+
expiredEvaluationLicenseKey
|
|
499
|
+
)) as ValidLicenseKeyResult
|
|
500
|
+
expect(result.isEvaluationLicense).toBe(true)
|
|
501
|
+
expect(result.isEvaluationLicenseExpired).toBe(true)
|
|
502
|
+
})
|
|
360
503
|
})
|
|
361
504
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
505
|
+
describe('License expiry and grace period', () => {
|
|
506
|
+
it('Fails if the license key has expired beyond grace period', async () => {
|
|
507
|
+
const expiredLicenseInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
508
|
+
const expiryDate = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 40) // 40 days ago (beyond 30-day grace period)
|
|
509
|
+
expiredLicenseInfo[PROPERTIES.EXPIRY_DATE] = expiryDate
|
|
510
|
+
const expiredLicenseKey = await generateLicenseKey(
|
|
511
|
+
JSON.stringify(expiredLicenseInfo),
|
|
512
|
+
keyPair
|
|
513
|
+
)
|
|
514
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
515
|
+
expiredLicenseKey
|
|
516
|
+
)) as ValidLicenseKeyResult
|
|
517
|
+
expect(result.isAnnualLicenseExpired).toBe(true)
|
|
518
|
+
})
|
|
519
|
+
|
|
520
|
+
it('Allows a grace period for expired licenses', async () => {
|
|
521
|
+
const almostExpiredLicenseInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
522
|
+
const expiryDate = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 5) // 5 days ago
|
|
523
|
+
almostExpiredLicenseInfo[PROPERTIES.EXPIRY_DATE] = expiryDate
|
|
524
|
+
const almostExpiredLicenseKey = await generateLicenseKey(
|
|
525
|
+
JSON.stringify(almostExpiredLicenseInfo),
|
|
526
|
+
keyPair
|
|
527
|
+
)
|
|
528
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
529
|
+
almostExpiredLicenseKey
|
|
530
|
+
)) as ValidLicenseKeyResult
|
|
531
|
+
expect(result.isAnnualLicenseExpired).toBe(false)
|
|
532
|
+
})
|
|
533
|
+
|
|
534
|
+
it('Handles grace period correctly - 20 days expired should still be within grace period', async () => {
|
|
535
|
+
const expiredLicenseInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
536
|
+
const expiredDate = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 20) // 20 days ago
|
|
537
|
+
expiredLicenseInfo[PROPERTIES.EXPIRY_DATE] = expiredDate.toISOString()
|
|
538
|
+
|
|
539
|
+
const expiredLicenseKey = await generateLicenseKey(
|
|
540
|
+
JSON.stringify(expiredLicenseInfo),
|
|
541
|
+
keyPair
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
// Test the getLicenseFromKey method to verify grace period calculation
|
|
545
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
546
|
+
expiredLicenseKey
|
|
547
|
+
)) as ValidLicenseKeyResult
|
|
548
|
+
expect(result.isAnnualLicense).toBe(true)
|
|
549
|
+
expect(result.isAnnualLicenseExpired).toBe(false) // Within 30-day grace period
|
|
550
|
+
expect(result.daysSinceExpiry).toBe(20)
|
|
551
|
+
})
|
|
552
|
+
|
|
553
|
+
it('Calculates days since expiry correctly', async () => {
|
|
554
|
+
const expiredLicenseInfo = JSON.parse(STANDARD_LICENSE_INFO)
|
|
555
|
+
const expiredDate = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 15) // 15 days ago
|
|
556
|
+
expiredLicenseInfo[PROPERTIES.EXPIRY_DATE] = expiredDate.toISOString()
|
|
557
|
+
|
|
558
|
+
const expiredLicenseKey = await generateLicenseKey(
|
|
559
|
+
JSON.stringify(expiredLicenseInfo),
|
|
560
|
+
keyPair
|
|
561
|
+
)
|
|
562
|
+
|
|
563
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
564
|
+
expiredLicenseKey
|
|
565
|
+
)) as ValidLicenseKeyResult
|
|
566
|
+
expect(result.daysSinceExpiry).toBe(15)
|
|
567
|
+
})
|
|
373
568
|
})
|
|
374
569
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
570
|
+
describe('Perpetual licenses', () => {
|
|
571
|
+
// We mock the patch version to be in 2030 above.
|
|
572
|
+
it('Succeeds for perpetual license with correct version (and patch does not matter)', async () => {
|
|
573
|
+
const majorDate = new Date(publishDates.major)
|
|
574
|
+
const expiryDate = new Date(
|
|
575
|
+
majorDate.getFullYear(),
|
|
576
|
+
majorDate.getMonth(),
|
|
577
|
+
majorDate.getDate() + 100
|
|
578
|
+
)
|
|
579
|
+
const perpetualLicenseInfo = ['id', ['www.example.com'], FLAGS.PERPETUAL_LICENSE, expiryDate]
|
|
580
|
+
const almostExpiredLicenseKey = await generateLicenseKey(
|
|
581
|
+
JSON.stringify(perpetualLicenseInfo),
|
|
582
|
+
keyPair
|
|
583
|
+
)
|
|
584
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
585
|
+
almostExpiredLicenseKey
|
|
586
|
+
)) as ValidLicenseKeyResult
|
|
587
|
+
expect(result.isPerpetualLicense).toBe(true)
|
|
588
|
+
expect(result.isPerpetualLicenseExpired).toBe(false)
|
|
589
|
+
})
|
|
590
|
+
|
|
591
|
+
it('Fails for perpetual license past the release version', async () => {
|
|
592
|
+
const majorDate = new Date(publishDates.major)
|
|
593
|
+
const expiryDate = new Date(
|
|
594
|
+
majorDate.getFullYear(),
|
|
595
|
+
majorDate.getMonth(),
|
|
596
|
+
majorDate.getDate() - 100
|
|
597
|
+
)
|
|
598
|
+
const perpetualLicenseInfo = ['id', ['www.example.com'], FLAGS.PERPETUAL_LICENSE, expiryDate]
|
|
599
|
+
const almostExpiredLicenseKey = await generateLicenseKey(
|
|
600
|
+
JSON.stringify(perpetualLicenseInfo),
|
|
601
|
+
keyPair
|
|
602
|
+
)
|
|
603
|
+
const result = (await licenseManager.getLicenseFromKey(
|
|
604
|
+
almostExpiredLicenseKey
|
|
605
|
+
)) as ValidLicenseKeyResult
|
|
606
|
+
expect(result.isPerpetualLicense).toBe(true)
|
|
607
|
+
expect(result.isPerpetualLicenseExpired).toBe(true)
|
|
608
|
+
})
|
|
386
609
|
})
|
|
387
610
|
})
|
|
388
611
|
|
|
@@ -469,12 +692,16 @@ function getDefaultLicenseResult(overrides: Partial<ValidLicenseKeyResult>): Val
|
|
|
469
692
|
isAnnualLicense: true,
|
|
470
693
|
isAnnualLicenseExpired: false,
|
|
471
694
|
isInternalLicense: false,
|
|
695
|
+
isNativeLicense: false,
|
|
472
696
|
isDevelopment: false,
|
|
473
697
|
isDomainValid: true,
|
|
474
698
|
isPerpetualLicense: false,
|
|
475
699
|
isPerpetualLicenseExpired: false,
|
|
476
700
|
isLicenseParseable: true as const,
|
|
477
701
|
isLicensedWithWatermark: false,
|
|
702
|
+
isEvaluationLicense: false,
|
|
703
|
+
isEvaluationLicenseExpired: false,
|
|
704
|
+
daysSinceExpiry: 0,
|
|
478
705
|
// WatermarkManager does not check these fields, it relies on the calculated values like isAnnualLicenseExpired
|
|
479
706
|
license: {
|
|
480
707
|
id: 'id',
|
|
@@ -487,115 +714,291 @@ function getDefaultLicenseResult(overrides: Partial<ValidLicenseKeyResult>): Val
|
|
|
487
714
|
}
|
|
488
715
|
}
|
|
489
716
|
|
|
490
|
-
describe(
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
717
|
+
describe('getLicenseState', () => {
|
|
718
|
+
describe('Development mode', () => {
|
|
719
|
+
it('returns "unlicensed" for unparseable license in development', () => {
|
|
720
|
+
const licenseResult = getDefaultLicenseResult({
|
|
721
|
+
// @ts-ignore
|
|
722
|
+
isLicenseParseable: false,
|
|
723
|
+
})
|
|
724
|
+
expect(getLicenseState(licenseResult, () => {}, true)).toBe('unlicensed')
|
|
495
725
|
})
|
|
496
|
-
expect(isEditorUnlicensed(licenseResult)).toBe(true)
|
|
497
|
-
})
|
|
498
726
|
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
727
|
+
it('returns "licensed" for invalid domain in development mode', () => {
|
|
728
|
+
const licenseResult = getDefaultLicenseResult({
|
|
729
|
+
isDomainValid: false,
|
|
730
|
+
isDevelopment: true,
|
|
731
|
+
})
|
|
732
|
+
expect(getLicenseState(licenseResult, () => {}, true)).toBe('licensed')
|
|
502
733
|
})
|
|
503
|
-
expect(isEditorUnlicensed(licenseResult)).toBe(true)
|
|
504
|
-
})
|
|
505
734
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
735
|
+
it('returns "licensed" for valid license in development mode', () => {
|
|
736
|
+
const licenseResult = getDefaultLicenseResult({
|
|
737
|
+
isDevelopment: true,
|
|
738
|
+
})
|
|
739
|
+
expect(getLicenseState(licenseResult, () => {}, true)).toBe('licensed')
|
|
510
740
|
})
|
|
511
|
-
expect(isEditorUnlicensed(licenseResult)).toBe(true)
|
|
512
|
-
})
|
|
513
741
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
742
|
+
it('returns "unlicensed" for no license key in development (localhost)', () => {
|
|
743
|
+
const licenseResult = getDefaultLicenseResult({
|
|
744
|
+
// @ts-ignore
|
|
745
|
+
isLicenseParseable: false,
|
|
746
|
+
reason: 'no-key-provided',
|
|
747
|
+
})
|
|
748
|
+
expect(getLicenseState(licenseResult, () => {}, true)).toBe('unlicensed')
|
|
519
749
|
})
|
|
520
|
-
expect(isEditorUnlicensed(licenseResult)).toBe(true)
|
|
521
750
|
})
|
|
522
751
|
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
752
|
+
describe('Production mode - unlicensed states', () => {
|
|
753
|
+
it('returns "unlicensed-production" for unparseable license in production (invalid-license-key)', () => {
|
|
754
|
+
const messages: string[][] = []
|
|
755
|
+
const licenseResult = getDefaultLicenseResult({
|
|
756
|
+
// @ts-ignore
|
|
757
|
+
isLicenseParseable: false,
|
|
758
|
+
reason: 'invalid-license-key',
|
|
759
|
+
})
|
|
760
|
+
const result = getLicenseState(licenseResult, (msgs) => messages.push(msgs), false)
|
|
761
|
+
expect(result).toBe('unlicensed-production')
|
|
762
|
+
|
|
763
|
+
expect(messages).toHaveLength(1)
|
|
764
|
+
expect(messages[0]).toEqual([
|
|
765
|
+
'Invalid license key. tldraw requires a valid license for production use.',
|
|
766
|
+
'Please reach out to sales@tldraw.com to purchase a license.',
|
|
767
|
+
])
|
|
527
768
|
})
|
|
528
|
-
expect(isEditorUnlicensed(licenseResult)).toBe(true)
|
|
529
|
-
})
|
|
530
769
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
770
|
+
it('returns "unlicensed-production" for no license key in production', () => {
|
|
771
|
+
const messages: string[][] = []
|
|
772
|
+
const licenseResult = getDefaultLicenseResult({
|
|
773
|
+
// @ts-ignore
|
|
774
|
+
isLicenseParseable: false,
|
|
775
|
+
reason: 'no-key-provided',
|
|
776
|
+
})
|
|
777
|
+
const result = getLicenseState(licenseResult, (msgs) => messages.push(msgs), false)
|
|
778
|
+
expect(result).toBe('unlicensed-production')
|
|
779
|
+
|
|
780
|
+
expect(messages).toHaveLength(1)
|
|
781
|
+
expect(messages[0]).toEqual([
|
|
782
|
+
'No tldraw license key provided!',
|
|
783
|
+
'A license is required for production deployments.',
|
|
784
|
+
'Please reach out to sales@tldraw.com to purchase a license.',
|
|
785
|
+
])
|
|
536
786
|
})
|
|
537
|
-
expect(isEditorUnlicensed(licenseResult)).toBe(false)
|
|
538
|
-
})
|
|
539
787
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
788
|
+
it('returns "unlicensed-production" for invalid license key in production', () => {
|
|
789
|
+
const messages: string[][] = []
|
|
790
|
+
const licenseResult = getDefaultLicenseResult({
|
|
791
|
+
// @ts-ignore
|
|
792
|
+
isLicenseParseable: false,
|
|
793
|
+
reason: 'invalid-license-key',
|
|
794
|
+
})
|
|
795
|
+
const result = getLicenseState(licenseResult, (msgs) => messages.push(msgs), false)
|
|
796
|
+
expect(result).toBe('unlicensed-production')
|
|
797
|
+
|
|
798
|
+
expect(messages).toHaveLength(1)
|
|
799
|
+
expect(messages[0]).toEqual([
|
|
800
|
+
'Invalid license key. tldraw requires a valid license for production use.',
|
|
801
|
+
'Please reach out to sales@tldraw.com to purchase a license.',
|
|
802
|
+
])
|
|
545
803
|
})
|
|
546
|
-
expect(isEditorUnlicensed(licenseResult)).toBe(false)
|
|
547
|
-
})
|
|
548
804
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
805
|
+
it('returns "unlicensed-production" for invalid domain in production', () => {
|
|
806
|
+
const messages: string[][] = []
|
|
807
|
+
const licenseResult = getDefaultLicenseResult({
|
|
808
|
+
isDomainValid: false,
|
|
809
|
+
isDevelopment: false,
|
|
810
|
+
})
|
|
811
|
+
const result = getLicenseState(licenseResult, (msgs) => messages.push(msgs), false)
|
|
812
|
+
expect(result).toBe('unlicensed-production')
|
|
813
|
+
|
|
814
|
+
expect(messages).toHaveLength(1)
|
|
815
|
+
expect(messages[0]).toEqual([
|
|
816
|
+
'License key is not valid for this domain.',
|
|
817
|
+
'A license is required for production deployments.',
|
|
818
|
+
'Please reach out to sales@tldraw.com to purchase a license.',
|
|
819
|
+
])
|
|
552
820
|
})
|
|
553
|
-
expect(isEditorUnlicensed(licenseResult)).toBe(false)
|
|
554
|
-
})
|
|
555
821
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
822
|
+
it('returns "unlicensed-production" for expired internal license with invalid domain', () => {
|
|
823
|
+
const messages: string[][] = []
|
|
824
|
+
const expiryDate = new Date(2023, 1, 1)
|
|
825
|
+
const licenseResult = getDefaultLicenseResult({
|
|
826
|
+
isAnnualLicense: true,
|
|
827
|
+
isAnnualLicenseExpired: true,
|
|
828
|
+
isInternalLicense: true,
|
|
829
|
+
isDomainValid: false,
|
|
830
|
+
expiryDate,
|
|
831
|
+
})
|
|
832
|
+
const result = getLicenseState(licenseResult, (msgs) => messages.push(msgs), false)
|
|
833
|
+
expect(result).toBe('unlicensed-production')
|
|
834
|
+
|
|
835
|
+
expect(messages).toHaveLength(1)
|
|
836
|
+
expect(messages[0]).toEqual([
|
|
837
|
+
'License key is not valid for this domain.',
|
|
838
|
+
'A license is required for production deployments.',
|
|
839
|
+
'Please reach out to sales@tldraw.com to purchase a license.',
|
|
840
|
+
])
|
|
560
841
|
})
|
|
561
|
-
expect(isEditorUnlicensed(licenseResult)).toBe(false)
|
|
562
842
|
})
|
|
563
843
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
844
|
+
describe('Valid licenses', () => {
|
|
845
|
+
it('returns "licensed" for valid annual license', () => {
|
|
846
|
+
const licenseResult = getDefaultLicenseResult({
|
|
847
|
+
isAnnualLicense: true,
|
|
848
|
+
isAnnualLicenseExpired: false,
|
|
849
|
+
})
|
|
850
|
+
expect(getLicenseState(licenseResult, () => {}, false)).toBe('licensed')
|
|
569
851
|
})
|
|
570
|
-
expect(isEditorUnlicensed(licenseResult)).toBe(false)
|
|
571
|
-
})
|
|
572
852
|
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
853
|
+
it('returns "licensed" for valid perpetual license', () => {
|
|
854
|
+
const licenseResult = getDefaultLicenseResult({
|
|
855
|
+
isPerpetualLicense: true,
|
|
856
|
+
isPerpetualLicenseExpired: false,
|
|
857
|
+
})
|
|
858
|
+
expect(getLicenseState(licenseResult, () => {}, false)).toBe('licensed')
|
|
859
|
+
})
|
|
860
|
+
|
|
861
|
+
it('returns "licensed-with-watermark" for watermarked license', () => {
|
|
862
|
+
const licenseResult = getDefaultLicenseResult({
|
|
863
|
+
isLicensedWithWatermark: true,
|
|
864
|
+
})
|
|
865
|
+
expect(getLicenseState(licenseResult, () => {}, false)).toBe('licensed-with-watermark')
|
|
866
|
+
})
|
|
867
|
+
|
|
868
|
+
it('returns "licensed" for valid evaluation license', () => {
|
|
869
|
+
const licenseResult = getDefaultLicenseResult({
|
|
870
|
+
isEvaluationLicense: true,
|
|
871
|
+
isLicensedWithWatermark: false, // Evaluation license doesn't need WITH_WATERMARK flag
|
|
872
|
+
isAnnualLicense: false,
|
|
873
|
+
isPerpetualLicense: false,
|
|
874
|
+
})
|
|
875
|
+
|
|
876
|
+
// Evaluation license should be licensed but tracked (no watermark shown)
|
|
877
|
+
expect(getLicenseState(licenseResult, () => {}, false)).toBe('licensed')
|
|
878
|
+
|
|
879
|
+
// Verify evaluation license properties
|
|
880
|
+
expect(licenseResult.isEvaluationLicense).toBe(true)
|
|
881
|
+
expect(licenseResult.isLicensedWithWatermark).toBe(false) // No explicit watermark flag needed
|
|
882
|
+
expect(licenseResult.isAnnualLicense).toBe(false)
|
|
883
|
+
expect(licenseResult.isPerpetualLicense).toBe(false)
|
|
580
884
|
})
|
|
581
|
-
expect(() => isEditorUnlicensed(licenseResult)).toThrow(/License: Internal license expired/)
|
|
582
885
|
})
|
|
583
886
|
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
887
|
+
describe('Grace period handling', () => {
|
|
888
|
+
it('returns "licensed" for license 0-30 days past expiry', () => {
|
|
889
|
+
const messages: string[][] = []
|
|
890
|
+
const licenseResult = getDefaultLicenseResult({
|
|
891
|
+
isAnnualLicense: true,
|
|
892
|
+
isAnnualLicenseExpired: false, // Still within 30-day grace period
|
|
893
|
+
daysSinceExpiry: 20, // 20 days past expiry
|
|
894
|
+
isInternalLicense: false,
|
|
895
|
+
})
|
|
896
|
+
|
|
897
|
+
expect(getLicenseState(licenseResult, (msgs) => messages.push(msgs), false)).toBe('licensed')
|
|
898
|
+
|
|
899
|
+
expect(messages).toHaveLength(1)
|
|
900
|
+
expect(messages[0]).toEqual([
|
|
901
|
+
'Your tldraw license has expired.',
|
|
902
|
+
'License expired 20 days ago.',
|
|
903
|
+
'Please reach out to sales@tldraw.com to renew your license.',
|
|
904
|
+
])
|
|
591
905
|
})
|
|
592
|
-
expect(() => isEditorUnlicensed(licenseResult)).toThrow(/License: Internal license expired/)
|
|
593
906
|
})
|
|
594
907
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
908
|
+
describe('Expired licenses', () => {
|
|
909
|
+
it('returns "expired" for license 30+ days past expiry', () => {
|
|
910
|
+
const messages: string[][] = []
|
|
911
|
+
const licenseResult = getDefaultLicenseResult({
|
|
912
|
+
isAnnualLicense: true,
|
|
913
|
+
isAnnualLicenseExpired: true, // Beyond 30-day grace period
|
|
914
|
+
daysSinceExpiry: 35, // 35 days past expiry
|
|
915
|
+
isInternalLicense: false,
|
|
916
|
+
})
|
|
917
|
+
|
|
918
|
+
expect(getLicenseState(licenseResult, (msgs) => messages.push(msgs), false)).toBe('expired')
|
|
919
|
+
|
|
920
|
+
expect(messages).toHaveLength(1)
|
|
921
|
+
expect(messages[0]).toEqual([
|
|
922
|
+
'Your tldraw license has been expired for more than 30 days!',
|
|
923
|
+
'Please reach out to sales@tldraw.com to renew your license.',
|
|
924
|
+
])
|
|
925
|
+
})
|
|
926
|
+
|
|
927
|
+
it('returns "expired" for expired annual license even in dev mode', () => {
|
|
928
|
+
const licenseResult = getDefaultLicenseResult({
|
|
929
|
+
isAnnualLicense: true,
|
|
930
|
+
isAnnualLicenseExpired: true,
|
|
931
|
+
isDevelopment: true,
|
|
932
|
+
isInternalLicense: false,
|
|
933
|
+
})
|
|
934
|
+
expect(getLicenseState(licenseResult, () => {}, true)).toBe('expired')
|
|
935
|
+
})
|
|
936
|
+
|
|
937
|
+
it('returns "expired" for expired perpetual license', () => {
|
|
938
|
+
const licenseResult = getDefaultLicenseResult({
|
|
939
|
+
isPerpetualLicense: true,
|
|
940
|
+
isPerpetualLicenseExpired: true,
|
|
941
|
+
isInternalLicense: false,
|
|
942
|
+
})
|
|
943
|
+
expect(getLicenseState(licenseResult, () => {}, false)).toBe('expired')
|
|
944
|
+
})
|
|
945
|
+
|
|
946
|
+
it('returns "expired" for expired evaluation license', () => {
|
|
947
|
+
const messages: string[][] = []
|
|
948
|
+
const licenseResult = getDefaultLicenseResult({
|
|
949
|
+
isEvaluationLicense: true,
|
|
950
|
+
isEvaluationLicenseExpired: true,
|
|
951
|
+
isAnnualLicense: false,
|
|
952
|
+
isPerpetualLicense: false,
|
|
953
|
+
})
|
|
954
|
+
|
|
955
|
+
expect(getLicenseState(licenseResult, (msgs) => messages.push(msgs), false)).toBe('expired')
|
|
956
|
+
|
|
957
|
+
expect(messages).toHaveLength(1)
|
|
958
|
+
expect(messages[0]).toEqual([
|
|
959
|
+
'Your tldraw evaluation license has expired!',
|
|
960
|
+
'Please reach out to sales@tldraw.com to purchase a full license.',
|
|
961
|
+
])
|
|
962
|
+
})
|
|
963
|
+
|
|
964
|
+
it('returns "expired" for expired internal annual license with valid domain', () => {
|
|
965
|
+
const messages: string[][] = []
|
|
966
|
+
const expiryDate = new Date(2023, 1, 1)
|
|
967
|
+
const licenseResult = getDefaultLicenseResult({
|
|
968
|
+
isAnnualLicense: true,
|
|
969
|
+
isAnnualLicenseExpired: true,
|
|
970
|
+
isInternalLicense: true,
|
|
971
|
+
isDomainValid: true,
|
|
972
|
+
expiryDate,
|
|
973
|
+
})
|
|
974
|
+
|
|
975
|
+
expect(getLicenseState(licenseResult, (msgs) => messages.push(msgs), false)).toBe('expired')
|
|
976
|
+
|
|
977
|
+
expect(messages).toHaveLength(1)
|
|
978
|
+
expect(messages[0]).toEqual([
|
|
979
|
+
'Your tldraw license has been expired for more than 30 days!',
|
|
980
|
+
'Please reach out to sales@tldraw.com to renew your license.',
|
|
981
|
+
])
|
|
982
|
+
})
|
|
983
|
+
|
|
984
|
+
it('returns "expired" for expired internal perpetual license with valid domain', () => {
|
|
985
|
+
const messages: string[][] = []
|
|
986
|
+
const expiryDate = new Date(2023, 1, 1)
|
|
987
|
+
const licenseResult = getDefaultLicenseResult({
|
|
988
|
+
isPerpetualLicense: true,
|
|
989
|
+
isPerpetualLicenseExpired: true,
|
|
990
|
+
isInternalLicense: true,
|
|
991
|
+
isDomainValid: true,
|
|
992
|
+
expiryDate,
|
|
993
|
+
})
|
|
994
|
+
|
|
995
|
+
expect(getLicenseState(licenseResult, (msgs) => messages.push(msgs), false)).toBe('expired')
|
|
996
|
+
|
|
997
|
+
expect(messages).toHaveLength(1)
|
|
998
|
+
expect(messages[0]).toEqual([
|
|
999
|
+
'Your tldraw license has been expired for more than 30 days!',
|
|
1000
|
+
'Please reach out to sales@tldraw.com to renew your license.',
|
|
1001
|
+
])
|
|
598
1002
|
})
|
|
599
|
-
expect(isEditorUnlicensed(licenseResult)).toBe(false)
|
|
600
1003
|
})
|
|
601
1004
|
})
|