Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,23 @@ jobs:
name: PSV / Linux Build / Tests / Code coverage
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
- name: Use Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v7
with:
node-version: 18
node-version: 24
cache: npm
# MockServer, which backs the functional tests, ships Java 17 bytecode.
# The runner defaults to Java 11, so pin the version the jar needs.
- name: Use Java
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: 17
- name: Build / Tests / Coverage
run: scripts/linux/psv/build_test_psv.sh
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
uses: codecov/codecov-action@v7
with:
fail_ci_if_error: true # optional (default = false)
verbose: true # optional (default = false)
Expand All @@ -33,7 +40,7 @@ jobs:
name: PSV.Commit.Checker
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Commit checker script. Verify commit text
Expand Down
13 changes: 10 additions & 3 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,19 @@ jobs:
echo "Package to deploy: $PACKAGE_NAME"
env:
PACKAGE_NAME: ${{ inputs.chooseDeploy }}
- uses: actions/checkout@v4
- uses: actions/checkout@v7
- name: Use Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v7
with:
node-version: '18'
node-version: '24'
cache: npm
# MockServer, which backs the functional tests, ships Java 17 bytecode.
# The runner defaults to Java 11, so pin the version the jar needs.
- name: Use Java
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: '17'
- name: Build / Tests
run: scripts/linux/psv/build_test_psv.sh && env
- name: Deploy to NPM
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ coverage
xunit.xml
*.js
!webpack.config.js
!scripts/static-server.js
*.d.ts
*.js.map
app.ts
Expand All @@ -22,6 +23,7 @@ heaptrack/
heaptrack_report.html
!tests/utils/mocked-olp-server/*.js
CertificateAuthorityCertificate.pem
mockserver-ca.pem
demo-app
build
.DS_Store
1 change: 1 addition & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
npx lint-staged
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v24
4 changes: 4 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"tabWidth": 4,
"trailingComma": "none"
}
3 changes: 0 additions & 3 deletions @here/olp-sdk-authentication/.prettierrc.json

This file was deleted.

25 changes: 13 additions & 12 deletions @here/olp-sdk-authentication/lib/UserAuth.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2020 HERE Europe B.V.
* Copyright (C) 2019-2026 HERE Europe B.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -18,6 +18,7 @@
*/

import { HttpError, SENT_WITH_PARAM } from "@here/olp-sdk-core";
import { buildErrorMessage } from "./buildErrorMessage";
import { OAuthArgs, Token } from "./requestToken_common";

/**
Expand Down Expand Up @@ -213,15 +214,13 @@ export class UserAuth {
);
}

const response = await this.config
.tokenRequester({
url: this.config.customUrl || this.m_apiUrl + "oauth2/token",
consumerKey: this.m_credentials.accessKeyId,
secretKey: this.m_credentials.accessKeySecret,
scope: this.m_scope,
expiresIn: this.m_expiresIn
})
.catch(err => Promise.reject(err));
const response = await this.config.tokenRequester({
url: this.config.customUrl || this.m_apiUrl + "oauth2/token",
consumerKey: this.m_credentials.accessKeyId,
secretKey: this.m_credentials.accessKeySecret,
scope: this.m_scope,
expiresIn: this.m_expiresIn
});

if (response.accessToken) {
this.m_accessToken = response.accessToken;
Expand Down Expand Up @@ -265,7 +264,7 @@ export class UserAuth {

if (!request.ok) {
return Promise.reject(
new HttpError(request.status, request.statusText)
new HttpError(request.status, await buildErrorMessage(request))
);
}

Expand Down Expand Up @@ -296,7 +295,9 @@ export class UserAuth {
return Promise.reject(
new HttpError(
request.status,
`Error fetching user info: ${request.statusText}`
`Error fetching user info: ${await buildErrorMessage(
request
)}`
)
);
}
Expand Down
46 changes: 46 additions & 0 deletions @here/olp-sdk-authentication/lib/buildErrorMessage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (C) 2026 HERE Europe B.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
* License-Filename: LICENSE
*/

/**
* Builds the description of a failed authentication request.
*
* The response body carries the `correlationId` and the error description
* reported by the platform. Both are needed to investigate a failure, so the
* body is appended to the status text. `statusText` is empty over HTTP/2, in
* which case the body becomes the whole message.
*
* @param response The failed response.
* @return The human-readable description of the failure.
*/
export async function buildErrorMessage(response: Response): Promise<string> {
// A body that cannot be read must not mask the HTTP error itself.
const rawBody =
typeof response.text === "function"
? await response.text().catch(() => "")
: "";
const body = rawBody.trim();

if (body.length === 0) {
return response.statusText;
}

return response.statusText.length > 0
? `${response.statusText} | Info: ${body}`
: body;
}
52 changes: 46 additions & 6 deletions @here/olp-sdk-authentication/lib/loadCredentialsFromFile.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019 HERE Europe B.V.
* Copyright (C) 2019-2026 HERE Europe B.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -17,9 +17,49 @@
* License-Filename: LICENSE
*/

import * as PropertiesReader from "properties-reader";
import * as fs from "fs";
import { AuthCredentials } from "./UserAuth";

/**
* Reads the `key = value` pairs of a **.properties** file.
*
* Only the subset of the format that the HERE platform emits is recognized:
* one pair per line, blank lines, and `#` or `!` comments. The value is
* everything after the first `=` or `:`, so values that themselves contain a
* separator (for example base64 padding in a secret) are kept intact.
*
* @param path The path to the file to read.
* @return The parsed properties, keyed by property name.
*/
function readProperties(path: string): Map<string, string> {
const properties = new Map<string, string>();

for (const line of fs.readFileSync(path, "utf8").split(/\r?\n/)) {
const entry = line.trim();

if (
entry.length === 0 ||
entry.startsWith("#") ||
entry.startsWith("!")
) {
continue;
}

const separator = entry.search(/[=:]/);

if (separator === -1) {
continue;
}

properties.set(
entry.slice(0, separator).trim(),
entry.slice(separator + 1).trim()
);
}

return properties;
}

/**
* Parses the **credentials.properties** file from the
* [HERE platform](https://developer.here.com/documentation/access-control/user-guide/topics/get-credentials.html)
Expand All @@ -30,21 +70,21 @@ import { AuthCredentials } from "./UserAuth";
* @return The object with the access key ID and access key secret.
*/
export function loadCredentialsFromFile(path: string): AuthCredentials {
const config = PropertiesReader(path);
const config = readProperties(path);
const configAccessKeyIdValueName = "here.access.key.id";
const configAccessKeySecretValueName = "here.access.key.secret";

const parseValueFromConfig = (
value: string | number | boolean | null,
value: string | undefined,
valueName: string
): string => {
if (!value) {
if (value === undefined || value.length === 0) {
throw new Error(
`Error parsing value ${valueName} from configuration`
);
}

return value.toString();
return value;
};

return {
Expand Down
7 changes: 4 additions & 3 deletions @here/olp-sdk-authentication/lib/requestToken_common.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2019-2020 HERE Europe B.V.
* Copyright (C) 2019-2026 HERE Europe B.V.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -22,6 +22,7 @@ import {
HttpError,
SENT_WITH_PARAM
} from "@here/olp-sdk-core";
import { buildErrorMessage } from "./buildErrorMessage";

/**
* Platform-specific parts of signing a request using HMAC algorithms.
Expand Down Expand Up @@ -97,7 +98,7 @@ async function signLatin1(
function generateUid(randomValues: Uint8Array): string {
const pad2 = (str: string) => (str.length === 1 ? "0" + str : str);
return randomValues.reduce(
(result, byte) => (result += pad2(byte.toString(UID_SIZE))),
(result, byte) => result + pad2(byte.toString(UID_SIZE)),
""
);
}
Expand Down Expand Up @@ -175,7 +176,7 @@ export async function requestToken_common(

if (!request.ok) {
return Promise.reject(
new HttpError(request.status, request.statusText)
new HttpError(request.status, await buildErrorMessage(request))
);
}

Expand Down
Loading