Skip to content

Commit 9e82d33

Browse files
committed
【feature】mvt解密支持SM4
1 parent 796c1d1 commit 9e82d33

File tree

9 files changed

+119
-24
lines changed

9 files changed

+119
-24
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@
140140
"@mapbox/mapbox-gl-style-spec": "^14.3.0",
141141
"@mapbox/vector-tile": "1.3.1",
142142
"@supermap/iclient-common": "file:src/common",
143-
"@supermap/tile-decryptor": "^0.0.2",
143+
"@supermapgis/tile-decryptor": "^1.0.0",
144144
"@turf/center": "^6.5.0",
145145
"@turf/turf": "6.5.0",
146146
"canvg": "3.0.10",

src/common/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
"license": "Apache-2.0",
1616
"dependencies": {
1717
"@antv/g6": "^4.8.14",
18-
"@supermap/tile-decryptor": "^0.0.2",
1918
"echarts": "5.5.0",
2019
"fetch-ie8": "1.5.0",
2120
"fetch-jsonp": "1.1.3",

src/common/util/EncryptRequest.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ export class EncryptRequest {
147147
* @category iServer Core
148148
* @description 获取矢量瓦片解密密钥
149149
* @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 - 矢量瓦片密钥
150+
* @return {Promise} options - 矢量瓦片密钥和加密算法类型。例如 { serviceKey, algorithm }
151151
* @usage
152152
* ```
153153
* // 浏览器
@@ -166,7 +166,7 @@ export class EncryptRequest {
166166
export async function getServiceKey(serviceUrl) {
167167
try {
168168
const workspaceServerUrl = ((serviceUrl &&
169-
serviceUrl.match(/.+(?=(\/restjsr\/v1\/vectortile\/|\/rest\/maps\/))/)) ||
169+
serviceUrl.match(/.+(?=(\/restjsr\/v1\/vectortile\/|\/rest\/maps\/|\/rest\/data\/))/)) ||
170170
[])[0];
171171
if (!workspaceServerUrl) {
172172
return;
@@ -187,7 +187,14 @@ export async function getServiceKey(serviceUrl) {
187187
method: 'get',
188188
url: svckeyUrl
189189
});
190-
return svcReponse.json();
190+
const serviceKey = await svcReponse.json();
191+
if (!serviceKey) {
192+
return;
193+
}
194+
return {
195+
serviceKey,
196+
algorithm: matchRestData.serviceEncryptInfo.encrptSpec.algorithm
197+
};
191198
} catch (error) {
192199
console.error(error);
193200
}

src/mapboxgl/core/MapExtend.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,13 @@ export var MapExtend = (function () {
1616
mapboxgl.VectorTileSource.prototype.beforeLoad = async function (id, options) {
1717
const url = options && options.tiles && options.tiles[0];
1818
if (decryptSources.values.includes(id) && url) {
19-
const decryptKey = await getServiceKey(url);
20-
this.decryptKey = decryptKey;
19+
const res = await getServiceKey(url);
20+
if (res) {
21+
this.decryptOptions = {
22+
key: res.serviceKey,
23+
algorithm: res.algorithm
24+
};
25+
}
2126
}
2227
this.beforeLoadBak(id, options);
2328
};

src/openlayers/overlay/VectorTileSuperMapRest.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import GeoJSON from 'ol/format/GeoJSON';
1717
import * as olSize from 'ol/size';
1818
import Projection from 'ol/proj/Projection';
1919
import TileGrid from 'ol/tilegrid/TileGrid';
20-
import decryptTileUtil from '@supermap/tile-decryptor';
20+
import decryptTileUtil from '@supermapgis/tile-decryptor';
2121

2222
/**
2323
* @class VectorTileSuperMapRest
@@ -34,7 +34,8 @@ import decryptTileUtil from '@supermap/tile-decryptor';
3434
* @param {(string|Object)} [options.attributions='Tile Data <span>© <a href='http://support.supermap.com.cn/product/iServer.aspx' target='_blank'>SuperMap iServer</a></span> with <span>© <a href='https://iclient.supermap.io' target='_blank'>SuperMap iClient</a></span>'] - 版权描述信息。
3535
* @param {Object} [options.format] - 瓦片的要素格式化。
3636
* @param {boolean} [options.withCredentials] - 请求是否携带 cookie。
37-
* @param {boolean} [options.decrypt] - 瓦片是否需要解密。
37+
* @param {boolean|Function} [options.decrypt] - 瓦片解密。如果是 true 表示用内置的解密方法, 如 decrypt: true;如果是function 则是自定义解密如 decrypt: function ({ key, bytes })。
38+
* @param {Function} [options.decryptCompletedFunction] - 解密完成后触发。如 decryptCompletedFunction(completeData)。
3839
* @extends {ol.source.VectorTile}
3940
* @usage
4041
*/
@@ -386,15 +387,23 @@ export class VectorTileSuperMapRest extends VectorTile {
386387
const firstSource = Object.keys(options.style.sources)[0];
387388
serviceUrl = options.style.sources[firstSource].tiles[0];
388389
}
389-
this.serviceKey = await getServiceKey(serviceUrl);
390+
const res = await getServiceKey(serviceUrl);
391+
if (res) {
392+
this.decryptOptions = {
393+
key: res.serviceKey,
394+
algorithm: res.algorithm,
395+
decrypt: typeof options.decrypt === 'boolean' ? undefined : options.decrypt,
396+
decryptCompletedFunction: options.decryptCompletedFunction
397+
};
398+
}
390399
} catch (error) {
391400
console.error(error);
392401
}
393402
}
394403

395404
_decryptMvt(mvtData) {
396-
if (this.serviceKey) {
397-
return decryptTileUtil(mvtData, this.serviceKey);
405+
if (this.decryptOptions) {
406+
return decryptTileUtil({ ...this.decryptOptions, arrayBuffer: mvtData });
398407
}
399408
return mvtData;
400409
}

src/openlayers/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,11 @@
1515
"author": "SuperMap",
1616
"license": "Apache-2.0",
1717
"dependencies": {
18+
"@supermap/iclient-common": "11.2.0",
19+
"@supermapgis/tile-decryptor": "^1.0.0",
1820
"@turf/turf": "6.5.0",
1921
"mapv": "2.0.62",
2022
"ol": "7.5.2",
21-
"@supermap/iclient-common": "11.2.0",
2223
"proj4": "2.11.0",
2324
"canvg": "3.0.10",
2425
"lodash.remove": "^4.7.0",

test/common/util/EncryptRequestSpec.js

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { FetchRequest } from '../../../src/common/util/FetchRequest';
2-
import { EncryptRequest } from '../../../src/common/util/EncryptRequest';
2+
import { EncryptRequest, getServiceKey } from '../../../src/common/util/EncryptRequest';
33

44
describe('EncryptRequest', () => {
55
const serverUrl = 'http://fake.iserver.com/iserver';
@@ -71,4 +71,63 @@ describe('EncryptRequest', () => {
7171
});
7272
});
7373
});
74+
75+
it('getServiceKey', (done) => {
76+
const serviceKey = 'l3nQtAUM4li87qMfO68exInHVFQ5gS3a6pb8ySIbib8=';
77+
const encrptSpec = {
78+
keyLength: 256,
79+
attributes: 'abcd',
80+
version: '1.1',
81+
algorithm: 'AES'
82+
};
83+
const spyEncrypt = spyOn(EncryptRequest.prototype, 'request').and.callFake((options) => {
84+
if (options.url.includes('keyID1')) {
85+
return { json: () => Promise.resolve(serviceKey)};
86+
}
87+
return { json: () => Promise.resolve(null)};
88+
});
89+
const spyGet = spyOn(FetchRequest, 'get').and.callFake((url) => {
90+
if (url.includes('map-China100')) {
91+
return Promise.resolve(
92+
new Response(
93+
JSON.stringify([
94+
{
95+
serviceEncryptInfo: {
96+
encrptSpec,
97+
updateTime: 'Fri Mar 15 08:52:15 CST 2024',
98+
encrptKeyID: 'keyID1'
99+
},
100+
name: 'map-China100/rest'
101+
}
102+
])
103+
)
104+
);
105+
}
106+
return Promise.resolve(
107+
new Response(
108+
JSON.stringify([
109+
{
110+
serviceEncryptInfo: {
111+
encrptSpec,
112+
updateTime: 'Fri Mar 15 08:52:15 CST 2024',
113+
encrptKeyID: 'keyID2'
114+
},
115+
name: 'data-china100/rest'
116+
}
117+
])
118+
)
119+
);
120+
});
121+
getServiceKey('http://localhost:8090/iserver/services/map-China100/rest/maps/China').then(res => {
122+
expect(res).not.toBeUndefined();
123+
expect(res.serviceKey).toBe(serviceKey);
124+
expect(res.algorithm).toBe(encrptSpec.algorithm);
125+
getServiceKey('http://localhost:8090/iserver/services/data-China100/rest/data/datasources/China/datasets/Airport_pt').then(res => {
126+
expect(res).toBeUndefined();
127+
spyGet.calls.reset();
128+
spyEncrypt.calls.reset();
129+
done();
130+
});
131+
});
132+
});
74133
});

test/mapboxgl/core/MapExtendSpec.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,8 @@ describe('MapExtend mapboxgl', () => {
236236
decryptSources.add('B');
237237
expect(decryptSources.values).toEqual(['A', 'B']);
238238
await vectorSource.beforeLoad('A', source);
239-
expect(vectorSource.decryptKey).toEqual('P8h08GonNjuCB4+CAykAGmLYwNsiv4G6H8KFrFi7Afk=');
239+
expect(vectorSource.decryptOptions.key).toBe('P8h08GonNjuCB4+CAykAGmLYwNsiv4G6H8KFrFi7Afk=');
240+
expect(vectorSource.decryptOptions.algorithm).toBe('AES');
240241
} catch (error) {
241242
expect(error).toEqual(new Error('mapbox-gl cannot support plane coordinate system.'));
242243
}

test/openlayers/overlay/VectorTileSuperMapRestSpec.js

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,19 +59,20 @@ const mapObject = {
5959
};
6060
describe('openlayers_VectorTileSuperMapRest', () => {
6161
var testDiv, map, vectorTileOptions, vectorTileSource, originalTimeout, vectorLayer, spyGet, spyPost, spyCommit;
62+
const encrptSpec = {
63+
keyLength: 256,
64+
attributes: 'abcd',
65+
version: '1.1',
66+
algorithm: 'AES'
67+
};
6268
const mockCallback = (testUrl) => {
6369
if ((url.match(/.+(?=(\/restjsr\/v1\/vectortile\/|\/rest\/maps\/))/) || [])[0] === testUrl) {
6470
return Promise.resolve(
6571
new Response(
6672
JSON.stringify([
6773
{
6874
serviceEncryptInfo: {
69-
encrptSpec: {
70-
keyLength: 256,
71-
attributes: 'abcd',
72-
version: '1.1',
73-
algorithm: 'AES'
74-
},
75+
encrptSpec,
7576
updateTime: 'Fri Mar 15 08:52:15 CST 2024',
7677
encrptKeyID: 'keyIDNAME'
7778
},
@@ -175,7 +176,8 @@ describe('openlayers_VectorTileSuperMapRest', () => {
175176

176177
it('mvt_decrypt ', (done) => {
177178
const spy = jasmine.createSpy('test');
178-
const spyEncrypt = spyOn(EncryptRequest.prototype, 'request').and.callFake(() => ({ json: () => Promise.resolve('l3nQtAUM4li87qMfO68exInHVFQ5gS3a6pb8ySIbib8=')}));
179+
const serviceKey = 'l3nQtAUM4li87qMfO68exInHVFQ5gS3a6pb8ySIbib8=';
180+
const spyEncrypt = spyOn(EncryptRequest.prototype, 'request').and.callFake(() => ({ json: () => Promise.resolve(serviceKey)}));
179181
new MapService(url).getMapInfo((serviceResult) => {
180182
map = new Map({
181183
target: 'map',
@@ -185,10 +187,11 @@ describe('openlayers_VectorTileSuperMapRest', () => {
185187
})
186188
});
187189
vectorTileOptions = VectorTileSuperMapRest.optionsFromMapJSON(url, serviceResult.result);
188-
vectorTileOptions.decrypt = true;
189190
vectorTileOptions.format = new MVT({
190191
featureClass: Feature
191192
});
193+
vectorTileOptions.decrypt = function() { return []};
194+
vectorTileOptions.decryptCompletedFunction = function() {};
192195
vectorTileOptions.tileLoadFunction = (tile) => {
193196
tile.setLoader(() => {
194197
spy();
@@ -204,7 +207,18 @@ describe('openlayers_VectorTileSuperMapRest', () => {
204207
expect(vectorTileOptions).not.toBeNull();
205208
expect(spy.calls.count()).toBe(1);
206209
expect(spyEncrypt).toHaveBeenCalled();
207-
expect(vectorTileSource.serviceKey).not.toBeUndefined();
210+
expect(vectorTileSource.decryptOptions).not.toBeUndefined();
211+
expect(vectorTileSource.decryptOptions.key).toBe(serviceKey);
212+
expect(vectorTileSource.decryptOptions.algorithm).toEqual(encrptSpec.algorithm);
213+
expect(vectorTileSource.decryptOptions.decrypt).not.toBeUndefined();
214+
expect(vectorTileSource.decryptOptions.decryptCompletedFunction).not.toBeUndefined();
215+
let testData = new Uint8Array();
216+
let resultData = vectorTileSource._decryptMvt(testData);
217+
expect(resultData.slice(0).join(',')).toEqual(testData.slice(0).join(','));
218+
vectorTileSource.decryptOptions = null;
219+
testData = new Uint8Array([5, 10]);
220+
resultData = vectorTileSource._decryptMvt(testData);
221+
expect(resultData.slice(0).join(',')).toEqual(testData.slice(0).join(','));
208222
spy.calls.reset();
209223
spyEncrypt.calls.reset();
210224
done();

0 commit comments

Comments
 (0)