Added ability to autogenerate checksum for firmware

This commit is contained in:
zbeacon 2021-04-28 12:26:35 +03:00
parent 7ce1fc77c9
commit 8a5a4f0995
8 changed files with 46 additions and 66 deletions

View File

@ -115,7 +115,7 @@ public class FirmwareController extends BaseController {
@ResponseBody @ResponseBody
public Firmware saveFirmwareData(@PathVariable(FIRMWARE_ID) String strFirmwareId, public Firmware saveFirmwareData(@PathVariable(FIRMWARE_ID) String strFirmwareId,
@RequestParam(required = false) String checksum, @RequestParam(required = false) String checksum,
@RequestParam(required = false) String checksumAlgorithm, @RequestParam() String checksumAlgorithm,
@RequestBody MultipartFile file) throws ThingsboardException { @RequestBody MultipartFile file) throws ThingsboardException {
checkParameter(FIRMWARE_ID, strFirmwareId); checkParameter(FIRMWARE_ID, strFirmwareId);
try { try {
@ -129,18 +129,17 @@ public class FirmwareController extends BaseController {
firmware.setVersion(info.getVersion()); firmware.setVersion(info.getVersion());
firmware.setAdditionalInfo(info.getAdditionalInfo()); firmware.setAdditionalInfo(info.getAdditionalInfo());
byte[] data = file.getBytes(); ByteBuffer data = ByteBuffer.wrap(file.getBytes());
if (StringUtils.isEmpty(checksumAlgorithm)) { if (StringUtils.isEmpty(checksum)) {
checksumAlgorithm = "sha256"; checksum = firmwareService.generateChecksum(checksumAlgorithm, data);
checksum = Hashing.sha256().hashBytes(data).toString();
} }
firmware.setChecksumAlgorithm(checksumAlgorithm); firmware.setChecksumAlgorithm(checksumAlgorithm);
firmware.setChecksum(checksum); firmware.setChecksum(checksum);
firmware.setFileName(file.getOriginalFilename()); firmware.setFileName(file.getOriginalFilename());
firmware.setContentType(file.getContentType()); firmware.setContentType(file.getContentType());
firmware.setData(ByteBuffer.wrap(data)); firmware.setData(data);
firmware.setDataSize((long) data.length); firmware.setDataSize((long) data.array().length);
return firmwareService.saveFirmware(firmware); return firmwareService.saveFirmware(firmware);
} catch (Exception e) { } catch (Exception e) {
throw handleException(e); throw handleException(e);

View File

@ -22,12 +22,16 @@ import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageData;
import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.page.PageLink;
import java.nio.ByteBuffer;
public interface FirmwareService { public interface FirmwareService {
FirmwareInfo saveFirmwareInfo(FirmwareInfo firmwareInfo); FirmwareInfo saveFirmwareInfo(FirmwareInfo firmwareInfo);
Firmware saveFirmware(Firmware firmware); Firmware saveFirmware(Firmware firmware);
String generateChecksum(String checksumAlgorithm, ByteBuffer data);
Firmware findFirmwareById(TenantId tenantId, FirmwareId firmwareId); Firmware findFirmwareById(TenantId tenantId, FirmwareId firmwareId);
FirmwareInfo findFirmwareInfoById(TenantId tenantId, FirmwareId firmwareId); FirmwareInfo findFirmwareInfoById(TenantId tenantId, FirmwareId firmwareId);

View File

@ -456,9 +456,6 @@ public class MqttTransportHandler extends ChannelInboundHandlerAdapter implement
deviceSessionCtx.getPayloadAdaptor() deviceSessionCtx.getPayloadAdaptor()
.convertToPublish(deviceSessionCtx, firmwareChunk, requestId, chunk) .convertToPublish(deviceSessionCtx, firmwareChunk, requestId, chunk)
.ifPresent(deviceSessionCtx.getChannel()::writeAndFlush); .ifPresent(deviceSessionCtx.getChannel()::writeAndFlush);
if (firmwareChunk != null && chunkSize != firmwareChunk.length) {
scheduler.schedule(() -> processDisconnect(ctx), 60, TimeUnit.SECONDS);
}
} catch (Exception e) { } catch (Exception e) {
log.trace("[{}] Failed to send firmware response!", sessionId, e); log.trace("[{}] Failed to send firmware response!", sessionId, e);
} }

View File

@ -101,6 +101,32 @@ public class BaseFirmwareService implements FirmwareService {
} }
} }
@Override
public String generateChecksum(String checksumAlgorithm, ByteBuffer data) {
if (data == null || !data.hasArray() || data.array().length == 0) {
throw new DataValidationException("Firmware data should be specified!");
}
HashFunction hashFunction;
switch (checksumAlgorithm) {
case "sha256":
hashFunction = Hashing.sha256();
break;
case "md5":
hashFunction = Hashing.md5();
break;
case "crc32":
hashFunction = Hashing.crc32();
break;
default:
throw new DataValidationException("Unknown checksum algorithm!");
}
return hashFunction.hashBytes(data.array()).toString();
}
@Override @Override
public Firmware findFirmwareById(TenantId tenantId, FirmwareId firmwareId) { public Firmware findFirmwareById(TenantId tenantId, FirmwareId firmwareId) {
log.trace("Executing findFirmwareById [{}]", firmwareId); log.trace("Executing findFirmwareById [{}]", firmwareId);
@ -217,11 +243,6 @@ public class BaseFirmwareService implements FirmwareService {
throw new DataValidationException("Firmware content type should be specified!"); throw new DataValidationException("Firmware content type should be specified!");
} }
ByteBuffer data = firmware.getData();
if (data == null || !data.hasArray() || data.array().length == 0) {
throw new DataValidationException("Firmware data should be specified!");
}
if (StringUtils.isEmpty(firmware.getChecksumAlgorithm())) { if (StringUtils.isEmpty(firmware.getChecksumAlgorithm())) {
throw new DataValidationException("Firmware checksum algorithm should be specified!"); throw new DataValidationException("Firmware checksum algorithm should be specified!");
} }
@ -229,22 +250,7 @@ public class BaseFirmwareService implements FirmwareService {
throw new DataValidationException("Firmware checksum should be specified!"); throw new DataValidationException("Firmware checksum should be specified!");
} }
HashFunction hashFunction; String currentChecksum = generateChecksum(firmware.getChecksumAlgorithm(), firmware.getData());
switch (firmware.getChecksumAlgorithm()) {
case "sha256":
hashFunction = Hashing.sha256();
break;
case "md5":
hashFunction = Hashing.md5();
break;
case "crc32":
hashFunction = Hashing.crc32();
break;
default:
throw new DataValidationException("Unknown checksum algorithm!");
}
String currentChecksum = hashFunction.hashBytes(data.array()).toString();
if (!currentChecksum.equals(firmware.getChecksum())) { if (!currentChecksum.equals(firmware.getChecksum())) {
throw new DataValidationException("Wrong firmware file!"); throw new DataValidationException("Wrong firmware file!");

View File

@ -20,7 +20,7 @@ import { PageLink } from '@shared/models/page/page-link';
import { defaultHttpOptionsFromConfig, defaultHttpUploadOptions, RequestConfig } from '@core/http/http-utils'; import { defaultHttpOptionsFromConfig, defaultHttpUploadOptions, RequestConfig } from '@core/http/http-utils';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { PageData } from '@shared/models/page/page-data'; import { PageData } from '@shared/models/page/page-data';
import { Firmware, FirmwareInfo } from '@shared/models/firmware.models'; import { ChecksumAlgorithm, Firmware, FirmwareInfo } from '@shared/models/firmware.models';
import { catchError, map, mergeMap } from 'rxjs/operators'; import { catchError, map, mergeMap } from 'rxjs/operators';
import { deepClone, isDefinedAndNotNull } from '@core/utils'; import { deepClone, isDefinedAndNotNull } from '@core/utils';
@ -100,16 +100,16 @@ export class FirmwareService {
return this.http.post<Firmware>('/api/firmware', firmware, defaultHttpOptionsFromConfig(config)); return this.http.post<Firmware>('/api/firmware', firmware, defaultHttpOptionsFromConfig(config));
} }
public uploadFirmwareFile(firmwareId: string, file: File, checksumAlgorithm?: string, public uploadFirmwareFile(firmwareId: string, file: File, checksumAlgorithm: ChecksumAlgorithm,
checksum?: string, config?: RequestConfig): Observable<any> { checksum?: string, config?: RequestConfig): Observable<any> {
if (!config) { if (!config) {
config = {}; config = {};
} }
const formData = new FormData(); const formData = new FormData();
formData.append('file', file); formData.append('file', file);
let url = `/api/firmware/${firmwareId}`; let url = `/api/firmware/${firmwareId}?checksumAlgorithm=${checksumAlgorithm}`;
if (checksumAlgorithm && checksum) { if (checksum) {
url += `?checksumAlgorithm=${checksumAlgorithm}&checksum=${checksum}`; url += `&checksum=${checksum}`;
} }
return this.http.post(url, formData, return this.http.post(url, formData,
defaultHttpUploadOptions(config.ignoreLoading, config.ignoreErrors, config.resendRequest)); defaultHttpUploadOptions(config.ignoreLoading, config.ignoreErrors, config.resendRequest));

View File

@ -72,7 +72,6 @@
<mat-label translate>firmware.checksum-algorithm</mat-label> <mat-label translate>firmware.checksum-algorithm</mat-label>
<input *ngIf="!isAdd" matInput formControlName="checksumAlgorithm" type="text" [readonly]="isEdit"> <input *ngIf="!isAdd" matInput formControlName="checksumAlgorithm" type="text" [readonly]="isEdit">
<mat-select formControlName="checksumAlgorithm" *ngIf="isAdd"> <mat-select formControlName="checksumAlgorithm" *ngIf="isAdd">
<mat-option [value]=null></mat-option>
<mat-option *ngFor="let checksumAlgorithm of checksumAlgorithms" [value]="checksumAlgorithm"> <mat-option *ngFor="let checksumAlgorithm of checksumAlgorithms" [value]="checksumAlgorithm">
{{ checksumAlgorithmTranslationMap.get(checksumAlgorithm) }} {{ checksumAlgorithmTranslationMap.get(checksumAlgorithm) }}
</mat-option> </mat-option>
@ -80,11 +79,7 @@
</mat-form-field> </mat-form-field>
<mat-form-field class="mat-block" fxFlex> <mat-form-field class="mat-block" fxFlex>
<mat-label translate>firmware.checksum</mat-label> <mat-label translate>firmware.checksum</mat-label>
<input matInput formControlName="checksum" type="text" [readonly]="!isAdd" <input matInput formControlName="checksum" type="text" [readonly]="!isAdd">
[required]="entityForm.get('checksumAlgorithm').value != null">
<mat-error *ngIf="entityForm.get('checksumAlgorithm').hasError('required')">
{{ 'firmware.checksum-required' | translate }}
</mat-error>
</mat-form-field> </mat-form-field>
</div> </div>
<section *ngIf="isAdd" style="padding-top: 8px"> <section *ngIf="isAdd" style="padding-top: 8px">

View File

@ -23,7 +23,6 @@ import { EntityTableConfig } from '@home/models/entity/entities-table-config.mod
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { EntityComponent } from '@home/components/entity/entity.component'; import { EntityComponent } from '@home/components/entity/entity.component';
import { ChecksumAlgorithm, ChecksumAlgorithmTranslationMap, Firmware } from '@shared/models/firmware.models'; import { ChecksumAlgorithm, ChecksumAlgorithmTranslationMap, Firmware } from '@shared/models/firmware.models';
import { distinctUntilChanged, map, takeUntil } from 'rxjs/operators';
import { ActionNotificationShow } from '@core/notification/notification.actions'; import { ActionNotificationShow } from '@core/notification/notification.actions';
@Component({ @Component({
@ -45,26 +44,6 @@ export class FirmwaresComponent extends EntityComponent<Firmware> implements OnI
super(store, fb, entityValue, entitiesTableConfigValue); super(store, fb, entityValue, entitiesTableConfigValue);
} }
ngOnInit() {
super.ngOnInit();
if (this.isAdd) {
this.entityForm.get('checksumAlgorithm').valueChanges.pipe(
map(algorithm => !!algorithm),
distinctUntilChanged(),
takeUntil(this.destroy$)
).subscribe(
setAlgorithm => {
if (setAlgorithm) {
this.entityForm.get('checksum').setValidators([Validators.maxLength(1020), Validators.required]);
} else {
this.entityForm.get('checksum').clearValidators();
}
this.entityForm.get('checksum').updateValueAndValidity({emitEvent: false});
}
);
}
}
ngOnDestroy() { ngOnDestroy() {
super.ngOnDestroy(); super.ngOnDestroy();
this.destroy$.next(); this.destroy$.next();
@ -83,7 +62,7 @@ export class FirmwaresComponent extends EntityComponent<Firmware> implements OnI
const form = this.fb.group({ const form = this.fb.group({
title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]], title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]],
version: [entity ? entity.version : '', [Validators.required, Validators.maxLength(255)]], version: [entity ? entity.version : '', [Validators.required, Validators.maxLength(255)]],
checksumAlgorithm: [entity ? entity.checksumAlgorithm : null], checksumAlgorithm: [entity && entity.checksumAlgorithm ? entity.checksumAlgorithm : ChecksumAlgorithm.SHA256],
checksum: [entity ? entity.checksum : '', Validators.maxLength(1020)], checksum: [entity ? entity.checksum : '', Validators.maxLength(1020)],
additionalInfo: this.fb.group( additionalInfo: this.fb.group(
{ {

View File

@ -38,8 +38,8 @@ export interface FirmwareInfo extends BaseData<FirmwareId> {
version?: string; version?: string;
hasData?: boolean; hasData?: boolean;
fileName: string; fileName: string;
checksum?: ChecksumAlgorithm; checksum?: string;
checksumAlgorithm?: string; checksumAlgorithm: ChecksumAlgorithm;
contentType: string; contentType: string;
dataSize?: number; dataSize?: number;
additionalInfo?: any; additionalInfo?: any;