- Add #domain, #protocol, #utils aliases to package.json imports map - Replace all relative imports (./, ../, ../..) in app/ and database/mongo_migrations/ with the corresponding #alias imports, eliminating relative path traversal across the codebase - Remove dead code: ConfigurationVersionModel.findByConfigurationIdentifier (unused, superseded by paginateVersions) and unused exception classes (NotFoundException, UnprocessableEntityException, DatabaseException) from app/exceptions/index.ts, keeping only BadRequestException - Fix pre-existing syntax error in configuration_version.ts (mismatched parenthesis) that broke tsc - Fix eqeqeq violation in configuration_service.ts and isNaN -> Number.isNaN in configuration_engine.ts / cwmp-1-0.ts / exchange_controller.ts - Fix no-shadow violation in cwmp-1-0.ts EventStruct constructor - Prettier formatting pass on touched files Validated: tsc --noEmit clean, eslint app/ clean, full test suite green.
216 lines
6.2 KiB
TypeScript
216 lines
6.2 KiB
TypeScript
import { randomBytes } from 'node:crypto'
|
|
import {
|
|
Cwmp_1_0,
|
|
Download,
|
|
FactoryReset,
|
|
type FaultCodeType,
|
|
FaultDetail,
|
|
FaultStruct,
|
|
Fault,
|
|
GetParameterAttributes,
|
|
GetParameterNames,
|
|
GetParameterValues,
|
|
InformResponse,
|
|
ParameterValueList,
|
|
Reboot,
|
|
ScheduleInform,
|
|
SetParameterAttributes,
|
|
SetParameterAttributesList,
|
|
SetParameterAttributesStruct,
|
|
AccessList,
|
|
SetParameterValues,
|
|
TransferCompleteResponse,
|
|
Upload,
|
|
} from '#protocol/cwmp-1-0'
|
|
import {
|
|
CwmpID,
|
|
NAMESPACES,
|
|
SoapEnvelope,
|
|
type SoapEnvelopeAttribute,
|
|
SoapEnvelopeHeader,
|
|
} from '#protocol/soap_envelope'
|
|
import type {
|
|
DownloadTaskPayload,
|
|
UploadTaskPayload,
|
|
SetParameterValuesTaskPayload,
|
|
SetParameterAttributesTaskPayload,
|
|
} from '#protocol/tr069_types'
|
|
|
|
function generateCwmpID(): string {
|
|
return randomBytes(4).toString('hex')
|
|
}
|
|
|
|
function makeEnvelope(cwmpId?: string): SoapEnvelope {
|
|
const enve = new SoapEnvelope()
|
|
enve.$ = NAMESPACES['1.0'] as SoapEnvelopeAttribute
|
|
enve.Header = new SoapEnvelopeHeader()
|
|
enve.Header.ID = new CwmpID({
|
|
$: { MustUnderstand: '1' },
|
|
_: cwmpId || generateCwmpID(),
|
|
})
|
|
enve.Body = new Cwmp_1_0()
|
|
return enve
|
|
}
|
|
|
|
export class CWMPMessageBuilder {
|
|
static informResponse(cwmpId?: string): string {
|
|
const enve = makeEnvelope(cwmpId)
|
|
enve.Body.InformResponse = new InformResponse({ MaxEnvelopes: 1 })
|
|
return enve.getXml()
|
|
}
|
|
|
|
static getParameterNames(
|
|
cwmpId: string | undefined,
|
|
parameterPath: string,
|
|
nextLevel: boolean = true
|
|
): string {
|
|
const enve = makeEnvelope(cwmpId)
|
|
enve.Body.GetParameterNames = new GetParameterNames({
|
|
ParameterPath: parameterPath,
|
|
NextLevel: nextLevel,
|
|
})
|
|
return enve.getXml()
|
|
}
|
|
|
|
static getParameterValues(cwmpId: string | undefined, parameterNames: string[]): string {
|
|
const enve = makeEnvelope(cwmpId)
|
|
enve.Body.GetParameterValues = new GetParameterValues({ ParameterNames: parameterNames })
|
|
return enve.getXml()
|
|
}
|
|
|
|
static setParameterValues(
|
|
cwmpId: string | undefined,
|
|
parameters: Array<{ name: string; value: string; type: string }>
|
|
): string {
|
|
const pvStructs = parameters.map((p) => ({
|
|
Name: p.name,
|
|
Value: { _: p.value, $: { Type: p.type } },
|
|
}))
|
|
const pvList = new ParameterValueList({
|
|
$: { ArrayType: `cwmp:ParameterValueStruct[${pvStructs.length}]` },
|
|
ParameterValueStruct: pvStructs,
|
|
})
|
|
const enve = makeEnvelope(cwmpId)
|
|
enve.Body.SetParameterValues = new SetParameterValues({
|
|
ParameterValueList: pvList,
|
|
ParameterKey: 'papaye-v2',
|
|
})
|
|
return enve.getXml()
|
|
}
|
|
|
|
static setParameterValuesFromPayload(
|
|
cwmpId: string | undefined,
|
|
payload: SetParameterValuesTaskPayload
|
|
): string {
|
|
const params = (payload.parameterValueList || []).map((p) => ({
|
|
name: p.Name,
|
|
value: String(p.Value?._ ?? ''),
|
|
type: p.Value?.$?.Type || 'xsd:string',
|
|
}))
|
|
return CWMPMessageBuilder.setParameterValues(cwmpId, params)
|
|
}
|
|
|
|
static download(cwmpId: string | undefined, params: DownloadTaskPayload): string {
|
|
const enve = makeEnvelope(cwmpId)
|
|
enve.Body.Download = new Download({
|
|
CommandKey: params.commandKey || '',
|
|
FileType: params.fileType || '1 Firmware Upgrade Image',
|
|
URL: params.url,
|
|
Username: params.username || '',
|
|
Password: params.password || '',
|
|
FileSize: params.fileSize || 0,
|
|
TargetFileName: params.targetFileName || '',
|
|
DelaySeconds: params.delaySeconds || 0,
|
|
SuccessURL: params.successUrl || '',
|
|
FailureURL: params.failureUrl || '',
|
|
})
|
|
return enve.getXml()
|
|
}
|
|
|
|
static upload(cwmpId: string | undefined, params: UploadTaskPayload): string {
|
|
const enve = makeEnvelope(cwmpId)
|
|
enve.Body.Upload = new Upload({
|
|
CommandKey: params.commandKey || '',
|
|
FileType: params.fileType || '3 Vendor Configuration File',
|
|
URL: params.url,
|
|
Username: params.username || '',
|
|
Password: params.password || '',
|
|
DelaySeconds: params.delaySeconds || 0,
|
|
})
|
|
return enve.getXml()
|
|
}
|
|
|
|
static reboot(cwmpId?: string, commandKey?: string): string {
|
|
const enve = makeEnvelope(cwmpId)
|
|
enve.Body.Reboot = new Reboot({ CommandKey: commandKey || '' })
|
|
return enve.getXml()
|
|
}
|
|
|
|
static factoryReset(cwmpId?: string): string {
|
|
const enve = makeEnvelope(cwmpId)
|
|
enve.Body.FactoryReset = new FactoryReset({})
|
|
return enve.getXml()
|
|
}
|
|
|
|
static scheduleInform(
|
|
cwmpId: string | undefined,
|
|
delaySeconds: number,
|
|
commandKey?: string
|
|
): string {
|
|
const enve = makeEnvelope(cwmpId)
|
|
enve.Body.ScheduleInform = new ScheduleInform({
|
|
DelaySeconds: delaySeconds,
|
|
CommandKey: commandKey || '',
|
|
})
|
|
return enve.getXml()
|
|
}
|
|
|
|
static getParameterAttributes(cwmpId: string | undefined, parameterNames: string[]): string {
|
|
const enve = makeEnvelope(cwmpId)
|
|
enve.Body.GetParameterAttributes = new GetParameterAttributes({
|
|
ParameterNames: parameterNames,
|
|
})
|
|
return enve.getXml()
|
|
}
|
|
|
|
static setParameterAttributes(
|
|
cwmpId: string | undefined,
|
|
attributes: SetParameterAttributesTaskPayload[]
|
|
): string {
|
|
const structs = attributes.map(
|
|
(a) =>
|
|
new SetParameterAttributesStruct({
|
|
Name: a.name,
|
|
NotificationChange: a.notificationChange,
|
|
Notification: a.notification,
|
|
AccessListChange: a.accessListChange,
|
|
AccessList: new AccessList({ string: a.accessList }),
|
|
})
|
|
)
|
|
const list = new SetParameterAttributesList({ SetParameterAttributesStruct: structs })
|
|
const enve = makeEnvelope(cwmpId)
|
|
enve.Body.SetParameterAttributes = new SetParameterAttributes({ ParameterList: list })
|
|
return enve.getXml()
|
|
}
|
|
|
|
static transferCompleteResponse(cwmpId?: string): string {
|
|
const enve = makeEnvelope(cwmpId)
|
|
enve.Body.TransferCompleteResponse = new TransferCompleteResponse({})
|
|
return enve.getXml()
|
|
}
|
|
|
|
static soapFault(faultCode: FaultCodeType, reason: string): string {
|
|
const fault = new Fault()
|
|
fault.Faultcode = 'Server'
|
|
fault.Faultstring = reason
|
|
fault.Detail = new FaultDetail({
|
|
Fault: new FaultStruct({ FaultCode: faultCode, FaultString: reason }),
|
|
})
|
|
return fault.getXml()
|
|
}
|
|
|
|
static emptyResponse(): string {
|
|
return ''
|
|
}
|
|
}
|