Skip to content

Commit 347eaf0

Browse files
[feature]mapboxgl解密矢量瓦片 review by songym
1 parent b107e78 commit 347eaf0

File tree

11 files changed

+363
-52
lines changed

11 files changed

+363
-52
lines changed

src/common/index.common.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,8 @@ import {
334334
getMeterPerMapUnit,
335335
getWrapNum,
336336
conversionDegree,
337-
EncryptRequest
337+
EncryptRequest,
338+
getServiceKey
338339
} from './util';
339340
import { CartoCSS, ThemeStyle } from './style';
340341
import {
@@ -500,6 +501,7 @@ export {
500501
setCORS,
501502
FetchRequest,
502503
EncryptRequest,
504+
getServiceKey,
503505
ColorsPickerUtil,
504506
ArrayStatistic,
505507
getMeterPerMapUnit,

src/common/namespace.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ import {
338338
setCORS,
339339
FetchRequest,
340340
EncryptRequest,
341+
getServiceKey,
341342
ColorsPickerUtil,
342343
ArrayStatistic,
343344
CartoCSS,
@@ -495,7 +496,7 @@ SuperMap.setRequestTimeout = setRequestTimeout;
495496
SuperMap.getRequestTimeout = getRequestTimeout;
496497
SuperMap.FetchRequest = FetchRequest;
497498
SuperMap.EncryptRequest = EncryptRequest;
498-
499+
SuperMap.getServiceKey = getServiceKey;
499500
// commontypes
500501
SuperMap.inherit = inheritExt;
501502
SuperMap.mixin = mixinExt;

src/common/util/EncryptRequest.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,41 @@ export class EncryptRequest {
140140
return this.tunnelUrl;
141141
}
142142
}
143+
144+
/**
145+
* @function getServiceKey
146+
* @version 11.2.0
147+
* @category iServer
148+
* @description 获取矢量瓦片解密密钥
149+
* @param {string} serviceUrl - iserver服务地址,例如: 'http://127.0.0.1:8090/iserver/services/xxx'、 'http://127.0.0.1:8090/iserver/services/xxx/rest/maps' 、 'http://127.0.0.1:8090/iserver/services/xxx/restjsr/v1/vectortile'
150+
* @return {Promise} key - 矢量瓦片密钥
151+
*/
152+
export async function getServiceKey(serviceUrl) {
153+
try {
154+
const workspaceServerUrl = ((serviceUrl &&
155+
serviceUrl.match(/.+(?=(\/restjsr\/v1\/vectortile\/|\/rest\/maps\/))/)) ||
156+
[])[0];
157+
if (!workspaceServerUrl) {
158+
return;
159+
}
160+
const servicesResponse = await FetchRequest.get(workspaceServerUrl);
161+
const servicesResult = await servicesResponse.json();
162+
const matchRestData = (servicesResult || []).find(
163+
(item) => serviceUrl.includes(item.name) && item.serviceEncryptInfo
164+
);
165+
if (!matchRestData) {
166+
return;
167+
}
168+
const iserverHost = workspaceServerUrl.split('/services/')[0];
169+
const encryptRequest = new EncryptRequest(iserverHost);
170+
const svckeyUrl =
171+
matchRestData && `${iserverHost}/services/security/svckeys/${matchRestData.serviceEncryptInfo.encrptKeyID}.json`;
172+
const svcReponse = await encryptRequest.request({
173+
method: 'get',
174+
url: svckeyUrl
175+
});
176+
return await svcReponse.json();
177+
} catch (error) {
178+
console.error(error);
179+
}
180+
}

src/common/util/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111

1212
import { ColorsPickerUtil } from './ColorsPickerUtil';
1313

14-
import { EncryptRequest } from './EncryptRequest';
14+
import { EncryptRequest, getServiceKey } from './EncryptRequest';
1515

1616
import { ArrayStatistic } from './ArrayStatistic';
1717
import { getMeterPerMapUnit, getWrapNum, conversionDegree } from './MapCalculateUtil';
@@ -73,6 +73,7 @@ export {
7373
getRequestTimeout,
7474
FetchRequest,
7575
EncryptRequest,
76+
getServiceKey,
7677
ColorsPickerUtil,
7778
ArrayStatistic,
7879
getMeterPerMapUnit,

src/mapboxgl/core/MapExtend.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,26 @@
22
* This program are made available under the terms of the Apache License, Version 2.0
33
* which accompanies this distribution and is available at http://www.apache.org/licenses/LICENSE-2.0.html.*/
44
import mapboxgl from 'mapbox-gl';
5+
import { decryptSources } from './decryptSource';
6+
import { getServiceKey } from '@supermap/iclient-common/util/EncryptRequest';
57

68
/**
79
* @function MapExtend
810
* @description 扩展了 mapboxgl.Map 对图层相关的操作。
911
* @private
1012
*/
1113
export var MapExtend = (function () {
14+
if (mapboxgl.VectorTileSource.prototype.beforeLoadBak === undefined) {
15+
mapboxgl.VectorTileSource.prototype.beforeLoadBak = mapboxgl.VectorTileSource.prototype.beforeLoad;
16+
mapboxgl.VectorTileSource.prototype.beforeLoad = async function (id, options) {
17+
const url = options && options.tiles && options.tiles[0];
18+
if (decryptSources.values.includes(id) && url) {
19+
const decryptKey = await getServiceKey(url);
20+
this.decryptKey = decryptKey;
21+
}
22+
this.beforeLoadBak(id, options);
23+
};
24+
}
1225
mapboxgl.Map.prototype.overlayLayersManager = {};
1326
if (mapboxgl.Map.prototype.addLayerBak === undefined) {
1427
mapboxgl.Map.prototype.addLayerBak = mapboxgl.Map.prototype.addLayer;

src/mapboxgl/core/decryptSource.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* @name decryptSources
3+
* @namespace
4+
* @category BaseTypes Util
5+
* @description 配置需要解密的矢量瓦片的sourceId。
6+
* @usage
7+
* ```
8+
* // 浏览器
9+
* <script type="text/javascript" src="{cdn}"></script>
10+
* <script>
11+
* const result = {namespace}.decryptSources.set(sourceIdsArray);
12+
*
13+
* </script>
14+
* // ES6 Import
15+
* import { decryptSources } from '{npm}';
16+
*
17+
* const result = decryptSources.set(sourceIdsArray);
18+
* ```
19+
*/
20+
const decryptSources = {
21+
values: [],
22+
/**
23+
* @function decryptSources.set
24+
* @description 设置需要解密的矢量瓦片的sourceId数组
25+
* @param {Array.<string>} sourceIds sourceId数组
26+
* @returns {Array.<string>} sourceId数组
27+
*/
28+
set(sourceIds) {
29+
this.values = sourceIds;
30+
return this.values;
31+
},
32+
/**
33+
* @function decryptSources.add
34+
* @description 添加需要解密的矢量瓦片的sourceId
35+
* @param {string} sourceId sourceId
36+
* @returns {Array.<string>} sourceId
37+
*/
38+
add(sourceId) {
39+
this.values.push(sourceId);
40+
return this.values;
41+
}
42+
};
43+
44+
export { decryptSources };

src/mapboxgl/core/index.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* Copyright© 2000 - 2023 SuperMap Software Co.Ltd. All rights reserved.
22
* This program are made available under the terms of the Apache License, Version 2.0
33
* which accompanies this distribution and is available at http://www.apache.org/licenses/LICENSE-2.0.html.*/
4-
export {Util} from './Util';
5-
export {MapExtend} from './MapExtend';
4+
export { Util } from './Util';
5+
export { MapExtend } from './MapExtend';
6+
export { decryptSources } from './decryptSource';

src/mapboxgl/namespace.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* This program are made available under the terms of the Apache License, Version 2.0
33
* which accompanies this distribution and is available at http://www.apache.org/licenses/LICENSE-2.0.html.*/
44
import { Logo } from './control';
5-
import { Util } from './core';
5+
import { Util, decryptSources } from './core';
66
import {
77
GraphThemeLayer,
88
LabelThemeLayer,
@@ -69,10 +69,10 @@ import mapboxgl from 'mapbox-gl';
6969

7070
mapboxgl.supermap = {...SuperMap, ...mapboxgl.supermap};
7171
mapboxgl.supermap.map = mapboxgl.supermap.map || {};
72-
7372
mapboxgl.supermap.LogoControl = Logo;
7473
mapboxgl.supermap.Logo = Logo;
7574
mapboxgl.supermap.Util = Util;
75+
mapboxgl.supermap.decryptSources = decryptSources;
7676
mapboxgl.supermap.WebMap = WebMap;
7777
mapboxgl.supermap.initMap = initMap;
7878
mapboxgl.supermap.Graphic = Graphic;

test/mapboxgl/core/MapExtendSpec.js

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
import mapboxgl from 'mapbox-gl';
2+
import mbglmap from '../../tool/mock_mapboxgl_map';
3+
import { FetchRequest } from '../../../src/common/util/FetchRequest';
4+
import cipher from 'node-forge/lib/cipher';
5+
import { MapExtend } from '../../../src/mapboxgl/core/MapExtend';
6+
import { decryptSources } from '../../../src/mapboxgl/core/decryptSource';
7+
8+
describe('getServiceKey', () => {
9+
let originalTimeout;
10+
const url = 'http:/fake:8090/iserver/iserver/services/map-China107/rest/maps/A';
11+
MapExtend;
12+
beforeEach(() => {
13+
spyOn(mapboxgl, 'Map').and.callFake(mbglmap);
14+
window.atob = () =>
15+
`ú\x86\x00ë\x14ø\n0Ø\x9C¶¬\x1D\x16ü\x99\x19rì;c\x8A\x8F\x83» þH©ü*TÂ.ÒxæêÏKëÔ|^¯à\x14*h\x96à\x80\x1E|\x8E¢\x8F)ÔÐ÷Á-/ì@iCð×F7û\x8B\x01k\x13\x18\x9BA\x88\x923]bSáÒLºÎ\v[váÐÁÆZi\x87\x1DþV\x91o\x97\x02~rÃñ¾\x051¥¬\x1CL\x01úºüê\x95\x0EEs¸/\\{6\x9A\x9DwRËÂ{¨~6T\x91\x19\x12\x1C_\x9Bb÷vhB\f{\x03éØ\x19w-Âϳ/\x1B»²C²\x1F\x97¢\x99\x88C\x8DÁCÂ8ð\x96t)ZùÞÓ\x03¨f\x1E´*\x97\x8Fµ±´í\x8B\x9ChíMlÅ\x06\x9Biþ\x03k¢\x83\x9A\x95\x8Fé\x03ùÓ¶N\x02qR?CÙê·Æ\x89\x854 ÞÐÒræéø¢]\x81ú®Ã0\x89ßMòPkå²E\x8DF\x1C¶æ\x84Bj¦\x99'[CÁ\x14ýaP\x1AÛu ×úHÃ:.\x1Eû\x0Eå\x0Féê\x91\x82ÓKÞ6T\x92é6©\x91v¨\f\x1A\x85·\x02¾\x87͵V[ç\x14DÑ8\x1Bm\x82ö\x1BBÿ\x87þí¬§f´¶\x9Fé\x1Ds¼:µt@\x15Í\x96bÛ"ý\x16~H0¥#l®\x02b`;
16+
cipher.createDecipher = () => ({
17+
start: () => {},
18+
update: () => {},
19+
finish: () => true,
20+
output: {
21+
data: `{"headers":{"X-Frame-Options":"SAMEORIGIN","Access-Control-Expose-Headers":"Access-Control-Allow-Origin,Access-Control-Allow-Credentials","Access-Control-Allow-Origin":"*","Set-Cookie":"rememberMe=deleteMe; Path=/iserver; Max-Age=0; Expires=Tue, 19-Mar-2024 01:43:12 GMT; SameSite=lax"},"data":"P8h08GonNjuCB4+CAykAGmLYwNsiv4G6H8KFrFi7Afk=","status":200}`
22+
}
23+
});
24+
spyOn(FetchRequest, 'get').and.callFake((url) => {
25+
if (url.includes('map-China107')) {
26+
return Promise.resolve(
27+
new Response(
28+
JSON.stringify([
29+
{
30+
componentType: 'com.supermap.services.components.impl.MapImpl',
31+
interfaceType: 'com.supermap.services.rest.RestServlet',
32+
additions: [
33+
'China',
34+
'China_4326',
35+
'ChinaDark',
36+
'China_4490',
37+
'China_4610',
38+
'China_4214',
39+
'China1',
40+
'China_Capital_pt@China',
41+
'A'
42+
],
43+
name: 'map-China107/rest',
44+
alias: 'map-China107',
45+
serviceEncryptInfo: {
46+
encrptSpec: {
47+
keyLength: 256,
48+
attributes: 'abcd',
49+
version: '1.1',
50+
algorithm: 'AES'
51+
},
52+
updateTime: 'Tue Mar 19 09:34:18 CST 2024',
53+
encrptKeyID: 'keyIDNAME'
54+
},
55+
url: 'http://fake:8090/iserver/services/map-China107/rest',
56+
status: 'OK'
57+
},
58+
{
59+
componentType: 'com.supermap.services.components.impl.MapImpl',
60+
interfaceType: 'com.supermap.services.rest.JaxrsServletForJersey',
61+
additions: [
62+
'China',
63+
'China_4326',
64+
'ChinaDark',
65+
'China_4490',
66+
'China_4610',
67+
'China_4214',
68+
'China1',
69+
'China_Capital_pt@China',
70+
'A'
71+
],
72+
name: 'map-China107/restjsr',
73+
alias: 'map-China107',
74+
serviceEncryptInfo: {
75+
encrptSpec: {
76+
keyLength: 256,
77+
attributes: 'abcd',
78+
version: '1.1',
79+
algorithm: 'AES'
80+
},
81+
updateTime: 'Tue Mar 19 09:34:18 CST 2024',
82+
encrptKeyID: 'keyIDNAME'
83+
},
84+
url: 'http://fake:8090/iserver/services/map-China107/restjsr',
85+
status: 'OK'
86+
}
87+
])
88+
)
89+
);
90+
}
91+
if (url.includes('publickey')) {
92+
return Promise.resolve(
93+
new Response(
94+
JSON.stringify({
95+
keyLength: 2048,
96+
publicKey:
97+
'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnYZxbL+oTbMDGQsFtVR674Zm/v04PhupLBrnm+BRja0bKV0zEsIWNUJ+fcOHBimCBPlU1ykZa2zibKRy+NOsfAIXUjd33Q8dPOOoF3m2ydbDxL7v6PB+f38jyXmvLd8EgyiMFuYUBvbnrHDPuodjWWUqNqdaBFl4wqp2fKTjsmsHevDwsf3plnCOu7mfsTemzCqlnD6W2uGbS71VI91VmYfIQMbExixAXjQ6CT35sV4b3CHmxhq+BrKnsiVpxvNrLkWrcli0DQDz1Opv7NdiGtw+bHNN2kxcQym/uDP3ClXDPmCYzsvB+GIW5GM78b7nsZjYy8VHjtyVdAkQwY27jQIDAQAB',
98+
keyScheme: 'PKCS#8'
99+
})
100+
)
101+
);
102+
}
103+
if (url.includes('vectorstyles')) {
104+
return Promise.resolve(new Response(JSON.stringify({})));
105+
}
106+
});
107+
spyOn(FetchRequest, 'post').and.callFake((url) => {
108+
if (
109+
url.includes(
110+
'tunnels/RmcvL1VHcVcyZU1ldXk5bW5rbGFTdkI4b1owWnRUVGg5K0E5aGo3MUQrTWRDbWdnMzhwSWlGSjRydFJoV0s4YjJlSjJZWHBoUnRRRnNMVDlLc3hmdXZDOFRqUnYzMUJtcXVqa0VTRE05Ukx2QjZLVTh2VGZUVzRndlM4Rmw4b1BsNTVNUVYzL215WXJIbkE4MC9GZzcrZnhrRUY2YUpsMmI1azBtQmljREZMUnREUkljdVBuWGFhK01jWmtUZDFUZjUxUnkwSlNsUFRuR1ZoWGV3VmZnOFI2bnM5K01yWWtPZm1kVnJManUxVmh5NUlIRmEyZXNUbzRHVDVKR3I2ZHpkOWVwRXFGdFdaMmxMMFM2YmhjNEorZHlvZXVQMmg3VGlCOGVYV1FJanE4bVYvcTNTRE5JRjRqR2RkSkJ6MENRSmVqcXpTbVdidnRxNm5jdDlmeDZBPT0='
111+
)
112+
) {
113+
return Promise.resolve(
114+
new Response(
115+
'4xwVfv35tWo01yLmIV8Yf5t+lJUl8kERVP9aOH+x/1iynjFKx6cpbxCPPCTvUK5RlX3xjFGMMz+hBTOt7Ke911tE8wlUkClWMNuDbJGdxuinM2BF9MyBd6U7NNiwSWvfk3tRdY8+sGlquYyXRRc1HTkKUSoaJNhqgx9xZMi740AxArOINgOqBnl1tS2i5R2MyjyJcrYDUfjb8wZL5LLU/y/jysUCBtiNrrdlY3hV1BgtWUSgHPdTSxXA595CbdK3Nx0DhGIhNCQWby9QJUDhTHAqsdcWYyTAozMf/J8Q8vmwf2pHEMbvWyq0Etstg6IJeUqcdPG2XNcmNX3/xpsgjseg1/AJhvMnv1morsXNsN+hDYg8NJgCyZ6fnTL2EC5y3ivhNgzccFIgPcaZRtAveOx3iiU8SAy9hP3tkR5toqeZsU//8awh4RZgFDDM+QKX7ipUVO+YihkIYmNlXwMMpsSg2SMKfeqUV/3D8CvxQZPlTA=='
116+
)
117+
);
118+
}
119+
if (url.includes('tunnels')) {
120+
return Promise.resolve(
121+
new Response(
122+
JSON.stringify({
123+
blockedUrlRegex: {
124+
DELETE: [],
125+
POST: [
126+
'.*/_setup/v2/querylicense.?(json|rjson)',
127+
'.*/services/security/login.?(json|rjson)',
128+
'.*/services/security/tokens.?(json|rjson)',
129+
'.*/manager/serviceSynchronizingJobs.?(json|rjson)',
130+
'.*/services/geoprocessing/restjsr/gpmodeler/runmodel',
131+
'.*/services/geoprocessing/restjsr/gpmodeler/modelui'
132+
],
133+
GET: [
134+
'.*/_setup/v2.?(json|rjson)',
135+
'.*/_setup/v2/currentlicense.?(json|rjson)',
136+
'.*/_setup.?(json|rjson)',
137+
'.*/_setup/currentuserlicenseinfo.?(json|rjson)',
138+
'.*/services/geoprocessing/restjsr/gpmodeler/list/.*/property',
139+
'.*/services/security/svckeys/[a-zA-Z]+\\.json'
140+
],
141+
PUT: [
142+
'.*/_setup/v2.?(json|rjson)',
143+
'.*/_setup/v2/querylicense.?(json|rjson)',
144+
'.*/_setup/v2/activelicense.?(json|rjson)',
145+
'.*/_setup.?(json|rjson)',
146+
'.*/_setup/cloudlicenselogin.?(json|rjson)',
147+
'.*/_setup/weblicense.?(json|rjson)',
148+
'.*/_setup/edulicense.?(json|rjson)',
149+
'.*/_setup/activecloudlicense.?(json|rjson)',
150+
'.*/_setup/activeWebLicense.?(json|rjson)',
151+
'.*/_setup/activeEduLicense.?(json|rjson)',
152+
'.*/services/security/profile.?(json|rjson)',
153+
'.*/manager/servicestorage.?(json|rjson)',
154+
'.*/services/geoprocessing/restjsr/gpmodeler/list/.*/property'
155+
]
156+
},
157+
tunnelUrl:
158+
'http://fake:8090/iserver/services/security/tunnel/v1/tunnels/RmcvL1VHcVcyZU1ldXk5bW5rbGFTdkI4b1owWnRUVGg5K0E5aGo3MUQrTWRDbWdnMzhwSWlGSjRydFJoV0s4YjJlSjJZWHBoUnRRRnNMVDlLc3hmdXZDOFRqUnYzMUJtcXVqa0VTRE05Ukx2QjZLVTh2VGZUVzRndlM4Rmw4b1BsNTVNUVYzL215WXJIbkE4MC9GZzcrZnhrRUY2YUpsMmI1azBtQmljREZMUnREUkljdVBuWGFhK01jWmtUZDFUZjUxUnkwSlNsUFRuR1ZoWGV3VmZnOFI2bnM5K01yWWtPZm1kVnJManUxVmh5NUlIRmEyZXNUbzRHVDVKR3I2ZHpkOWVwRXFGdFdaMmxMMFM2YmhjNEorZHlvZXVQMmg3VGlCOGVYV1FJanE4bVYvcTNTRE5JRjRqR2RkSkJ6MENRSmVqcXpTbVdidnRxNm5jdDlmeDZBPT0='
159+
})
160+
)
161+
);
162+
}
163+
});
164+
originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
165+
jasmine.DEFAULT_TIMEOUT_INTERVAL = 50000;
166+
});
167+
168+
afterEach(() => {
169+
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
170+
});
171+
172+
it('getServiceKey', async () => {
173+
try {
174+
const source = {
175+
tiles: [
176+
'http://172.16.13.234:8090/iserver/services/map-China107/rest/maps/A/tileFeature.mvt?returnAttributes=true&width=512&height=512&z={z}&x={x}&y={y}'
177+
],
178+
bounds: [-180, -90, 180, 90],
179+
type: 'vector'
180+
};
181+
const vectorSource = new mapboxgl.VectorTileSource('A', source, () => {}, {});
182+
await vectorSource.beforeLoad('A', source);
183+
expect(vectorSource.decryptKey).toEqual(undefined);
184+
decryptSources.set(['A']);
185+
decryptSources.add('B');
186+
expect(decryptSources.values).toEqual(['A', 'B']);
187+
await vectorSource.beforeLoad('A', source);
188+
expect(vectorSource.decryptKey).toEqual('P8h08GonNjuCB4+CAykAGmLYwNsiv4G6H8KFrFi7Afk=');
189+
} catch (error) {
190+
expect(error).toEqual(new Error('mapbox-gl cannot support plane coordinate system.'));
191+
}
192+
});
193+
});

test/test-main-mapboxgl.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,4 @@ import './mapboxgl/services/ChartServiceSpec';
7575
/*mapboxgl -- mapping*/
7676
import './mapboxgl/mapping/WebMapSpec.js';
7777
import './mapboxgl/mapping/InitMapSpec.js';
78+
import './mapboxgl/core/MapExtendSpec.js';

0 commit comments

Comments
 (0)