musicbrainz-api 0.10.3 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/lib/digest-auth.d.ts +2 -2
- package/lib/digest-auth.js +6 -6
- package/lib/musicbrainz-api.d.ts +12 -14
- package/lib/musicbrainz-api.js +15 -12
- package/lib/musicbrainz.types.d.ts +2 -1
- package/lib/rate-limiter.d.ts +1 -1
- package/lib/rate-limiter.js +2 -2
- package/lib/xml/xml-isrc-list.d.ts +1 -1
- package/lib/xml/xml-recording.d.ts +2 -2
- package/package.json +9 -4
- package/.idea/checkstyle-idea.xml +0 -16
- package/.idea/inspectionProfiles/Project_Default.xml +0 -7
- package/.idea/misc.xml +0 -6
- package/.idea/modules.xml +0 -8
- package/.idea/vcs.xml +0 -6
- package/lib/digest-auth.ts +0 -101
- package/lib/musicbrainz-api.ts +0 -794
- package/lib/musicbrainz.types.ts +0 -689
- package/lib/rate-limiter.ts +0 -34
- package/lib/xml/xml-isrc-list.ts +0 -20
- package/lib/xml/xml-isrc.ts +0 -15
- package/lib/xml/xml-metadata.ts +0 -30
- package/lib/xml/xml-recording.ts +0 -19
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ We are looking into making this package usable in the browser as well.
|
|
|
25
25
|
|
|
26
26
|
## Before using this library
|
|
27
27
|
|
|
28
|
-
MusicBrainz asks that you [
|
|
28
|
+
MusicBrainz asks that you to [identify your application](https://wiki.musicbrainz.org/Development/XML_Web_Service/Version_2#User%20Data) by filling in the ['User-Agent' Header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent).
|
|
29
29
|
By passing `appName`, `appVersion`, `appMail` musicbrainz-api takes care of that.
|
|
30
30
|
|
|
31
31
|
## Submitting metadata
|
package/lib/digest-auth.d.ts
CHANGED
|
@@ -12,10 +12,10 @@ export declare class DigestAuth {
|
|
|
12
12
|
* If the algorithm directive's value is "MD5-sess", then HA1 is
|
|
13
13
|
* HA1=MD5(MD5(username:realm:password):nonce:cnonce)
|
|
14
14
|
*/
|
|
15
|
-
static ha1Compute(algorithm:
|
|
15
|
+
static ha1Compute(algorithm: string, user: string, realm: string, pass: string, nonce: string, cnonce: string): string;
|
|
16
16
|
hasAuth: boolean;
|
|
17
17
|
sentAuth: boolean;
|
|
18
|
-
bearerToken: string;
|
|
18
|
+
bearerToken: string | null;
|
|
19
19
|
constructor(credentials: ICredentials);
|
|
20
20
|
digest(method: string, path: string, authHeader: string): string;
|
|
21
21
|
}
|
package/lib/digest-auth.js
CHANGED
|
@@ -64,16 +64,16 @@ class DigestAuth {
|
|
|
64
64
|
opaque: challenge.opaque
|
|
65
65
|
};
|
|
66
66
|
const parts = [];
|
|
67
|
-
|
|
68
|
-
if (
|
|
69
|
-
if (
|
|
70
|
-
parts.push(
|
|
67
|
+
Object.entries(authValues).forEach(([key, value]) => {
|
|
68
|
+
if (value) {
|
|
69
|
+
if (key === 'qop' || key === 'nc' || key === 'algorithm') {
|
|
70
|
+
parts.push(key + '=' + value);
|
|
71
71
|
}
|
|
72
72
|
else {
|
|
73
|
-
parts.push(
|
|
73
|
+
parts.push(key + '="' + value + '"');
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
|
-
}
|
|
76
|
+
});
|
|
77
77
|
authHeader = 'Digest ' + parts.join(', ');
|
|
78
78
|
this.sentAuth = true;
|
|
79
79
|
return authHeader;
|
package/lib/musicbrainz-api.d.ts
CHANGED
|
@@ -42,13 +42,13 @@ export type ReleaseGroupIncludes = MiscIncludes | SubQueryIncludes | RelationsIn
|
|
|
42
42
|
export type SeriesIncludes = MiscIncludes | RelationsIncludes;
|
|
43
43
|
export type WorkIncludes = MiscIncludes | RelationsIncludes;
|
|
44
44
|
export type UrlIncludes = RelationsIncludes;
|
|
45
|
-
export
|
|
45
|
+
export type IFormData = {
|
|
46
46
|
[key: string]: string | number;
|
|
47
|
-
}
|
|
47
|
+
};
|
|
48
48
|
export interface IMusicBrainzConfig {
|
|
49
|
-
botAccount
|
|
50
|
-
username
|
|
51
|
-
password
|
|
49
|
+
botAccount: {
|
|
50
|
+
username?: string;
|
|
51
|
+
password?: string;
|
|
52
52
|
};
|
|
53
53
|
baseUrl?: string;
|
|
54
54
|
appName?: string;
|
|
@@ -62,11 +62,12 @@ export interface IMusicBrainzConfig {
|
|
|
62
62
|
*/
|
|
63
63
|
appContactInfo?: string;
|
|
64
64
|
}
|
|
65
|
+
export interface ICsrfSession {
|
|
66
|
+
sessionKey: string;
|
|
67
|
+
token: string;
|
|
68
|
+
}
|
|
65
69
|
export interface ISessionInformation {
|
|
66
|
-
csrf:
|
|
67
|
-
sessionKey: string;
|
|
68
|
-
token: string;
|
|
69
|
-
};
|
|
70
|
+
csrf: ICsrfSession;
|
|
70
71
|
loggedIn?: boolean;
|
|
71
72
|
}
|
|
72
73
|
export declare class MusicBrainzApi {
|
|
@@ -74,11 +75,8 @@ export declare class MusicBrainzApi {
|
|
|
74
75
|
readonly config: IMusicBrainzConfig;
|
|
75
76
|
private rateLimiter;
|
|
76
77
|
private options;
|
|
77
|
-
private session
|
|
78
|
-
static fetchCsrf(html: string):
|
|
79
|
-
sessionKey: string;
|
|
80
|
-
token: string;
|
|
81
|
-
};
|
|
78
|
+
private session?;
|
|
79
|
+
static fetchCsrf(html: string): ICsrfSession;
|
|
82
80
|
private static fetchValue;
|
|
83
81
|
private getCookies;
|
|
84
82
|
constructor(_config?: IMusicBrainzConfig);
|
package/lib/musicbrainz-api.js
CHANGED
|
@@ -30,8 +30,9 @@ Object.defineProperty(exports, "XmlRecording", { enumerable: true, get: function
|
|
|
30
30
|
const digest_auth_1 = require("./digest-auth");
|
|
31
31
|
const rate_limiter_1 = require("./rate-limiter");
|
|
32
32
|
const mb = require("./musicbrainz.types");
|
|
33
|
+
/* eslint-disable-next-line */
|
|
33
34
|
const got_1 = require("got");
|
|
34
|
-
const
|
|
35
|
+
const tough_cookie_1 = require("tough-cookie");
|
|
35
36
|
__exportStar(require("./musicbrainz.types"), exports);
|
|
36
37
|
const util_1 = require("util");
|
|
37
38
|
const retries = 3;
|
|
@@ -86,10 +87,11 @@ class MusicBrainzApi {
|
|
|
86
87
|
}
|
|
87
88
|
constructor(_config) {
|
|
88
89
|
this.config = {
|
|
89
|
-
baseUrl: 'https://musicbrainz.org'
|
|
90
|
+
baseUrl: 'https://musicbrainz.org',
|
|
91
|
+
botAccount: {}
|
|
90
92
|
};
|
|
91
93
|
Object.assign(this.config, _config);
|
|
92
|
-
const cookieJar = new
|
|
94
|
+
const cookieJar = new tough_cookie_1.CookieJar();
|
|
93
95
|
this.getCookies = (0, util_1.promisify)(cookieJar.getCookies.bind(cookieJar));
|
|
94
96
|
this.options = {
|
|
95
97
|
prefixUrl: this.config.baseUrl,
|
|
@@ -97,7 +99,7 @@ class MusicBrainzApi {
|
|
|
97
99
|
headers: {
|
|
98
100
|
'User-Agent': `${this.config.appName}/${this.config.appVersion} ( ${this.config.appContactInfo} )`
|
|
99
101
|
},
|
|
100
|
-
cookieJar
|
|
102
|
+
cookieJar: cookieJar
|
|
101
103
|
};
|
|
102
104
|
this.rateLimiter = new rate_limiter_1.RateLimiter(60, 50);
|
|
103
105
|
}
|
|
@@ -353,7 +355,7 @@ class MusicBrainzApi {
|
|
|
353
355
|
const clientId = `${this.config.appName.replace(/-/g, '.')}-${this.config.appVersion}`;
|
|
354
356
|
const path = `ws/2/${entity}/`;
|
|
355
357
|
// Get digest challenge
|
|
356
|
-
let digest
|
|
358
|
+
let digest;
|
|
357
359
|
let n = 1;
|
|
358
360
|
const postData = xmlMetadata.toXml();
|
|
359
361
|
do {
|
|
@@ -384,7 +386,7 @@ class MusicBrainzApi {
|
|
|
384
386
|
}
|
|
385
387
|
}
|
|
386
388
|
}
|
|
387
|
-
this.session = await this.getSession(
|
|
389
|
+
this.session = await this.getSession();
|
|
388
390
|
const redirectUri = '/success';
|
|
389
391
|
const formData = {
|
|
390
392
|
username: this.config.botAccount.username,
|
|
@@ -411,7 +413,7 @@ class MusicBrainzApi {
|
|
|
411
413
|
returnto: redirectUri
|
|
412
414
|
} }, this.options));
|
|
413
415
|
const success = response.statusCode === http_status_codes_1.StatusCodes.MOVED_TEMPORARILY && response.headers.location === redirectUri;
|
|
414
|
-
if (success) {
|
|
416
|
+
if (success && this.session) {
|
|
415
417
|
this.session.loggedIn = true;
|
|
416
418
|
}
|
|
417
419
|
return success;
|
|
@@ -424,7 +426,7 @@ class MusicBrainzApi {
|
|
|
424
426
|
*/
|
|
425
427
|
async editEntity(entity, mbid, formData) {
|
|
426
428
|
await this.rateLimiter.limit();
|
|
427
|
-
this.session = await this.getSession(
|
|
429
|
+
this.session = await this.getSession();
|
|
428
430
|
formData.csrf_session_key = this.session.csrf.sessionKey;
|
|
429
431
|
formData.csrf_token = this.session.csrf.token;
|
|
430
432
|
formData.username = this.config.botAccount.username;
|
|
@@ -444,15 +446,16 @@ class MusicBrainzApi {
|
|
|
444
446
|
* @param editNote Edit note
|
|
445
447
|
*/
|
|
446
448
|
async addUrlToRecording(recording, url2add, editNote = '') {
|
|
449
|
+
var _a;
|
|
447
450
|
const formData = {};
|
|
448
451
|
formData['edit-recording.name'] = recording.title; // Required
|
|
449
452
|
formData['edit-recording.comment'] = recording.disambiguation;
|
|
450
453
|
formData['edit-recording.make_votable'] = true;
|
|
451
454
|
formData['edit-recording.url.0.link_type_id'] = url2add.linkTypeId;
|
|
452
455
|
formData['edit-recording.url.0.text'] = url2add.text;
|
|
453
|
-
|
|
454
|
-
formData[`edit-recording.isrcs.${i}`] =
|
|
455
|
-
}
|
|
456
|
+
(_a = recording.isrcs) === null || _a === void 0 ? void 0 : _a.forEach((isrcs, i) => {
|
|
457
|
+
formData[`edit-recording.isrcs.${i}`] = isrcs;
|
|
458
|
+
});
|
|
456
459
|
formData['edit-recording.edit_note'] = editNote;
|
|
457
460
|
return this.editEntity('recording', recording.id, formData);
|
|
458
461
|
}
|
|
@@ -527,7 +530,7 @@ class MusicBrainzApi {
|
|
|
527
530
|
searchUrl(query) {
|
|
528
531
|
return this.search('url', query);
|
|
529
532
|
}
|
|
530
|
-
async getSession(
|
|
533
|
+
async getSession() {
|
|
531
534
|
const response = await got_1.default.get('login', Object.assign({ followRedirect: false, responseType: 'text' }, this.options));
|
|
532
535
|
return {
|
|
533
536
|
csrf: MusicBrainzApi.fetchCsrf(response.body)
|
|
@@ -33,7 +33,7 @@ export interface IArtist extends IEntity {
|
|
|
33
33
|
disambiguation: string;
|
|
34
34
|
'sort-name': string;
|
|
35
35
|
'type-id'?: string;
|
|
36
|
-
'gender-id'?:
|
|
36
|
+
'gender-id'?: string;
|
|
37
37
|
'life-span'?: IPeriod;
|
|
38
38
|
country?: string;
|
|
39
39
|
ipis?: any[];
|
|
@@ -183,6 +183,7 @@ export interface IAreaList extends ISearchResult {
|
|
|
183
183
|
}
|
|
184
184
|
export interface IReleaseList extends ISearchResult {
|
|
185
185
|
releases: IReleaseMatch[];
|
|
186
|
+
'release-count': number;
|
|
186
187
|
}
|
|
187
188
|
export interface IReleaseGroupList extends ISearchResult {
|
|
188
189
|
'release-groups': IReleaseGroupMatch[];
|
package/lib/rate-limiter.d.ts
CHANGED
package/lib/rate-limiter.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RateLimiter = void 0;
|
|
4
|
-
const
|
|
5
|
-
const debug =
|
|
4
|
+
const debug_1 = require("debug");
|
|
5
|
+
const debug = (0, debug_1.default)('musicbrainz-api:rate-limiter');
|
|
6
6
|
class RateLimiter {
|
|
7
7
|
static sleep(ms) {
|
|
8
8
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
@@ -8,7 +8,7 @@ export declare class XmlRecording {
|
|
|
8
8
|
attrs: {
|
|
9
9
|
id: string;
|
|
10
10
|
};
|
|
11
|
-
children: {
|
|
11
|
+
children: ({
|
|
12
12
|
name: string;
|
|
13
13
|
attrs: {
|
|
14
14
|
count: number;
|
|
@@ -19,6 +19,6 @@ export declare class XmlRecording {
|
|
|
19
19
|
id: string;
|
|
20
20
|
};
|
|
21
21
|
}[];
|
|
22
|
-
}[];
|
|
22
|
+
} | null)[];
|
|
23
23
|
};
|
|
24
24
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "musicbrainz-api",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "MusicBrainz API client for reading and submitting metadata",
|
|
5
5
|
"main": "lib/musicbrainz-api",
|
|
6
6
|
"types": "lib/musicbrainz-api",
|
|
@@ -45,13 +45,14 @@
|
|
|
45
45
|
"json-stringify-safe": "^5.0.1",
|
|
46
46
|
"jsontoxml": "^1.0.1",
|
|
47
47
|
"source-map-support": "^0.5.16",
|
|
48
|
-
"tough-cookie": "^4.
|
|
48
|
+
"tough-cookie": "^4.1.3",
|
|
49
49
|
"uuid": "^9.0.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@types/chai": "^4.3.0",
|
|
53
|
+
"@types/jsontoxml": "^1.0.5",
|
|
53
54
|
"@types/mocha": "^9.0.0",
|
|
54
|
-
"@types/node": "^
|
|
55
|
+
"@types/node": "^20.8.10",
|
|
55
56
|
"@typescript-eslint/eslint-plugin": "^5.13.0",
|
|
56
57
|
"@typescript-eslint/parser": "^5.13.0",
|
|
57
58
|
"chai": "^4.2.0",
|
|
@@ -60,7 +61,7 @@
|
|
|
60
61
|
"eslint-config-prettier": "^8.4.0",
|
|
61
62
|
"eslint-import-resolver-typescript": "^3.3.0",
|
|
62
63
|
"eslint-plugin-import": "^2.25.4",
|
|
63
|
-
"eslint-plugin-jsdoc": "^
|
|
64
|
+
"eslint-plugin-jsdoc": "^46.8.2",
|
|
64
65
|
"eslint-plugin-node": "^11.1.0",
|
|
65
66
|
"eslint-plugin-unicorn": "^46.0.0",
|
|
66
67
|
"mocha": "^9.0.1",
|
|
@@ -71,6 +72,10 @@
|
|
|
71
72
|
"tslint": "^6.1.1",
|
|
72
73
|
"typescript": "^5.0.2"
|
|
73
74
|
},
|
|
75
|
+
"files": [
|
|
76
|
+
"lib/**/*.js",
|
|
77
|
+
"lib/**/*.d.ts"
|
|
78
|
+
],
|
|
74
79
|
"scripts": {
|
|
75
80
|
"clean": "del-cli lib/**/*.js lib/**/*.js.map lib/**/*.d.ts test/**/*.js test/**/*.js.map",
|
|
76
81
|
"compile-lib": "tsc -p lib",
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<project version="4">
|
|
3
|
-
<component name="CheckStyle-IDEA" serialisationVersion="2">
|
|
4
|
-
<checkstyleVersion>10.5.0</checkstyleVersion>
|
|
5
|
-
<scanScope>JavaOnly</scanScope>
|
|
6
|
-
<copyLibs>true</copyLibs>
|
|
7
|
-
<option name="thirdPartyClasspath" />
|
|
8
|
-
<option name="activeLocationIds" />
|
|
9
|
-
<option name="locations">
|
|
10
|
-
<list>
|
|
11
|
-
<ConfigurationLocation id="bundled-sun-checks" type="BUNDLED" scope="All" description="Sun Checks">(bundled)</ConfigurationLocation>
|
|
12
|
-
<ConfigurationLocation id="bundled-google-checks" type="BUNDLED" scope="All" description="Google Checks">(bundled)</ConfigurationLocation>
|
|
13
|
-
</list>
|
|
14
|
-
</option>
|
|
15
|
-
</component>
|
|
16
|
-
</project>
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
<component name="InspectionProjectProfileManager">
|
|
2
|
-
<profile version="1.0">
|
|
3
|
-
<option name="myName" value="Project Default" />
|
|
4
|
-
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
|
5
|
-
<inspection_tool class="TsLint" enabled="true" level="WARNING" enabled_by_default="true" />
|
|
6
|
-
</profile>
|
|
7
|
-
</component>
|
package/.idea/misc.xml
DELETED
package/.idea/modules.xml
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<project version="4">
|
|
3
|
-
<component name="ProjectModuleManager">
|
|
4
|
-
<modules>
|
|
5
|
-
<module fileurl="file://$PROJECT_DIR$/.idea/musicbrainz-api.iml" filepath="$PROJECT_DIR$/.idea/musicbrainz-api.iml" />
|
|
6
|
-
</modules>
|
|
7
|
-
</component>
|
|
8
|
-
</project>
|
package/.idea/vcs.xml
DELETED
package/lib/digest-auth.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import { v4 as uuidv4 } from 'uuid';
|
|
2
|
-
import * as crypto from 'crypto';
|
|
3
|
-
|
|
4
|
-
interface IChallenge {
|
|
5
|
-
algorithm?: string;
|
|
6
|
-
realm?: string;
|
|
7
|
-
nonce?: string;
|
|
8
|
-
opaque?: string;
|
|
9
|
-
qop?: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface ICredentials {
|
|
13
|
-
username: string;
|
|
14
|
-
password: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function md5(str) {
|
|
18
|
-
return crypto.createHash('md5').update(str).digest('hex'); // lgtm [js/insufficient-password-hash]
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export class DigestAuth {
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* RFC 2617: handle both MD5 and MD5-sess algorithms.
|
|
25
|
-
*
|
|
26
|
-
* If the algorithm directive's value is "MD5" or unspecified, then HA1 is
|
|
27
|
-
* HA1=MD5(username:realm:password)
|
|
28
|
-
* If the algorithm directive's value is "MD5-sess", then HA1 is
|
|
29
|
-
* HA1=MD5(MD5(username:realm:password):nonce:cnonce)
|
|
30
|
-
*/
|
|
31
|
-
public static ha1Compute(algorithm, user, realm, pass, nonce, cnonce) {
|
|
32
|
-
const ha1 = md5(user + ':' + realm + ':' + pass); // lgtm [js/insufficient-password-hash]
|
|
33
|
-
return algorithm && algorithm.toLowerCase() === 'md5-sess' ? md5(ha1 + ':' + nonce + ':' + cnonce) : ha1;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
public hasAuth: boolean;
|
|
37
|
-
public sentAuth: boolean;
|
|
38
|
-
public bearerToken: string;
|
|
39
|
-
|
|
40
|
-
public constructor(private credentials: ICredentials) {
|
|
41
|
-
this.hasAuth = false;
|
|
42
|
-
this.sentAuth = false;
|
|
43
|
-
this.bearerToken = null;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
public digest(method: string, path: string, authHeader: string): string {
|
|
47
|
-
// TODO: More complete implementation of RFC 2617.
|
|
48
|
-
// - support qop="auth-int" only
|
|
49
|
-
// - handle Authentication-Info (not necessarily?)
|
|
50
|
-
// - check challenge.stale (not necessarily?)
|
|
51
|
-
// - increase nc (not necessarily?)
|
|
52
|
-
// For reference:
|
|
53
|
-
// http://tools.ietf.org/html/rfc2617#section-3
|
|
54
|
-
// https://github.com/bagder/curl/blob/master/lib/http_digest.c
|
|
55
|
-
|
|
56
|
-
const challenge: IChallenge = {};
|
|
57
|
-
const re = /([a-z0-9_-]+)=(?:"([^"]+)"|([a-z0-9_-]+))/gi;
|
|
58
|
-
while (true) {
|
|
59
|
-
const match = re.exec(authHeader);
|
|
60
|
-
if (!match) {
|
|
61
|
-
break;
|
|
62
|
-
}
|
|
63
|
-
challenge[match[1]] = match[2] || match[3];
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const qop = /(^|,)\s*auth\s*($|,)/.test(challenge.qop) && 'auth';
|
|
67
|
-
const nc = qop && '00000001';
|
|
68
|
-
const cnonce = qop && uuidv4().replace(/-/g, '');
|
|
69
|
-
const ha1 = DigestAuth.ha1Compute(challenge.algorithm, this.credentials.username, challenge.realm, this.credentials.password, challenge.nonce, cnonce);
|
|
70
|
-
const ha2 = md5(method + ':' + path); // lgtm [js/insufficient-password-hash]
|
|
71
|
-
const digestResponse = qop
|
|
72
|
-
? md5(ha1 + ':' + challenge.nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + ha2) // lgtm [js/insufficient-password-hash]
|
|
73
|
-
: md5(ha1 + ':' + challenge.nonce + ':' + ha2); // lgtm [js/insufficient-password-hash]
|
|
74
|
-
const authValues = {
|
|
75
|
-
username: this.credentials.username,
|
|
76
|
-
realm: challenge.realm,
|
|
77
|
-
nonce: challenge.nonce,
|
|
78
|
-
uri: path,
|
|
79
|
-
qop,
|
|
80
|
-
response: digestResponse,
|
|
81
|
-
nc,
|
|
82
|
-
cnonce,
|
|
83
|
-
algorithm: challenge.algorithm,
|
|
84
|
-
opaque: challenge.opaque
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const parts: string[] = [];
|
|
88
|
-
for (const k in authValues) {
|
|
89
|
-
if (authValues[k]) {
|
|
90
|
-
if (k === 'qop' || k === 'nc' || k === 'algorithm') {
|
|
91
|
-
parts.push(k + '=' + authValues[k]);
|
|
92
|
-
} else {
|
|
93
|
-
parts.push(k + '="' + authValues[k] + '"');
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
authHeader = 'Digest ' + parts.join(', ');
|
|
98
|
-
this.sentAuth = true;
|
|
99
|
-
return authHeader;
|
|
100
|
-
}
|
|
101
|
-
}
|