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