• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Lumieducation / H5P-Nodejs-library / 1ac82faf-d7f3-4396-8f01-c8863a09cb5b

23 Jan 2025 07:17PM UTC coverage: 63.52% (-2.1%) from 65.668%
1ac82faf-d7f3-4396-8f01-c8863a09cb5b

push

circleci

web-flow
fix(h5p-server): added sanization of text strings without formatting (#3894)

* fix(h5p-server): plain text strings are now sanitized

* test: make tests happy with new H5Ps schemas

* test: removed more tests

5685 of 10188 branches covered (55.8%)

Branch coverage included in aggregate %.

1 of 1 new or added line in 1 file covered. (100.0%)

114 existing lines in 11 files now uncovered.

7651 of 10807 relevant lines covered (70.8%)

384.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

62.16
/packages/h5p-server/src/ContentFileScanner.ts
1
import { ContentScanner } from './ContentScanner';
24✔
2
import Logger from './helpers/Logger';
24✔
3
import LibraryManager from './LibraryManager';
4
import { ILibraryName, ISemanticsEntry } from './types';
5

6
const log = new Logger('ContentFileScanner');
24✔
7

8
/**
9
 * Describes a reference to a file that is embedded inside the content.
10
 */
11
export interface IFileReference {
12
    /**
13
     * Information about where the file reference was found
14
     */
15
    context: {
16
        /**
17
         * The path of the object **inside the params tree**. You can use this
18
         * path to later modify the params, if needed.
19
         */
20
        jsonPath: string;
21
        /**
22
         * The raw parameters of the object.
23
         */
24
        params: any;
25
        /**
26
         * The semantic structure of the object (as defined in semantics.json).
27
         *
28
         * Can be null or undefined if there is no semantic structure for the
29
         * element (happens if the file can be found somewhere that is not
30
         * described by the semantics)
31
         */
32
        semantics?: ISemanticsEntry;
33
    };
34
    /**
35
     * The path of the file **inside the H5P content directory** as can be used
36
     * to reference it in ContentManager (without any suffixes like #tmp).
37
     */
38
    filePath: string;
39
    /**
40
     * The mime type specified in the params
41
     */
42
    mimeType?: string;
43
    /**
44
     * If true, the file was marked as temporary (by the #tmp suffix). The
45
     * suffix is **not included** in filePath
46
     */
47
    temporary: boolean;
48
}
49

50
/**
51
 * Scans the content parameters (=content.json) of a piece of content and
52
 * returns a list of references to file that are embedded inside the content.
53
 */
54
export class ContentFileScanner extends ContentScanner {
24✔
55
    constructor(libraryManager: LibraryManager) {
56
        super(libraryManager);
114✔
57
        log.info('initialize');
114✔
58
    }
59

60
    /**
61
     * Used to differentiate between local files and URLs.
62
     */
63
    private static urlRegExp: RegExp = /^https?:\/\//;
24✔
64

65
    /**
66
     * Loads the specified content from the ContentManager and scans its
67
     * parameters (= content.json) for references to local files (= audio,
68
     * video, images, generic files).
69
     * @param contentId the content to scan
70
     * @param user the user who wants to access the file
71
     * @returns a list of local files
72
     */
73
    public async scanForFiles(
24✔
74
        mainParams: any,
75
        mainLibraryName: ILibraryName
76
    ): Promise<IFileReference[]> {
77
        const results: IFileReference[] = [];
122✔
78
        await this.scanContent(
244✔
79
            mainParams,
80
            mainLibraryName,
81
            (semantics, params, jsonPath) => {
82
                log.debug(
664✔
83
                    `Checking entry ${jsonPath} (type ${semantics.type})`
84
                );
85
                switch (semantics.type) {
664!
86
                    case 'file':
87
                    case 'image':
88
                        log.debug(`found ${semantics.type} element`);
112✔
89
                        const element = this.pushIfDefined(
112✔
90
                            results,
91
                            this.checkFileElement(semantics, params, jsonPath)
92
                        );
93
                        if (element) {
112✔
94
                            log.debug(
112✔
95
                                `Found file is a reference to ${element.filePath}`
96
                            );
97
                        }
98
                        if (params.originalImage) {
112!
UNCOV
99
                            const originalImageElement = this.pushIfDefined(
×
100
                                results,
101
                                this.checkFileElement(
102
                                    null,
103
                                    params.originalImage,
104
                                    `${jsonPath}.originalImage`
105
                                )
106
                            );
UNCOV
107
                            if (originalImageElement) {
×
UNCOV
108
                                log.debug(
×
109
                                    `Found file is a reference to ${originalImageElement.filePath}`
110
                                );
111
                            }
112
                        }
113
                        return true; // returning true aborts further recursion
112✔
114
                    case 'video':
115
                    case 'audio':
UNCOV
116
                        if (Array.isArray(params)) {
×
UNCOV
117
                            for (
×
UNCOV
118
                                let index = 0;
×
119
                                index < params.length;
120
                                index += 1
121
                            ) {
UNCOV
122
                                const arrayElement = this.pushIfDefined(
×
123
                                    results,
124
                                    this.checkFileElement(
125
                                        null,
126
                                        params[index],
127
                                        `${jsonPath}[${index}]`
128
                                    )
129
                                );
UNCOV
130
                                if (arrayElement) {
×
UNCOV
131
                                    log.debug(
×
132
                                        `Found file is a reference to ${arrayElement.filePath}`
133
                                    );
134
                                }
135
                            }
136
                        }
UNCOV
137
                        return true; // returning true aborts further recursion
×
138
                    default:
139
                        return false;
552✔
140
                }
141
            }
142
        );
143
        return results;
122✔
144
    }
145

146
    /**
147
     * Checks if an element in the parameter tree contains a valid reference to
148
     * a local file and removes temporary markers.
149
     * @param semantics The semantic structure of the element to check
150
     * @param params the parameter object of the element to check
151
     * @param jsonPath the JSONPath at which the element can be found in the
152
     * parameter object
153
     * @returns an object with information about the file reference; undefined
154
     * if the file reference is invalid
155
     */
156
    private checkFileElement(
24✔
157
        semantics: ISemanticsEntry,
158
        params: any,
159
        jsonPath: string
160
    ): IFileReference {
161
        if (!params.path) {
112!
162
            // Path shouldn't be empty, but we simply ignore the entry in this
163
            // case.
UNCOV
164
            return undefined;
×
165
        }
166
        if (ContentFileScanner.urlRegExp.test(params.path)) {
112!
167
            // If the file is a reference to a URL, we don't return it.
UNCOV
168
            return undefined;
×
169
        }
170

171
        let temporary = false;
112✔
172
        let cleanFileReferencePath = params.path;
112✔
173
        if (params.path.endsWith('#tmp')) {
112✔
174
            // files marked as temporary will be identified as such
175
            temporary = true;
38✔
176
            cleanFileReferencePath = params.path.substr(
38✔
177
                0,
178
                params.path.length - 4
179
            );
180
        }
181

182
        return {
112✔
183
            context: { semantics, params, jsonPath },
184
            filePath: cleanFileReferencePath,
185
            mimeType: params.mime,
186
            temporary
187
        };
188
    }
189

190
    /**
191
     * Helper function that pushes an item to an array if the item is defined.
192
     * @param array the array to push to
193
     * @param item the item to push
194
     * @returns the item (if defined); otherwise undefined
195
     */
196
    private pushIfDefined<T>(array: T[], item: T): T {
24✔
197
        if (item !== undefined) {
112✔
198
            array.push(item);
112✔
199
            return item;
112✔
200
        }
UNCOV
201
        return undefined;
×
202
    }
203
}
24✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc