Skip to content

Commit

Permalink
Merge pull request #75 from Hacksore/develop
Browse files Browse the repository at this point in the history
  • Loading branch information
Hacksore authored Oct 15, 2020
2 parents 5b1ee7a + 0205479 commit f3051a5
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 11 deletions.
111 changes: 108 additions & 3 deletions __tests__/vehicle.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,13 +129,118 @@ describe('EuropeanVehicle', () => {
expect(vehicle.nickname()).toEqual('Jest is best');
});

it('call status commmand', async () => {
// mock the enterPin request
it('refresh expired access token', async () => {
// create session with expired access token
vehicle.controller.session = {
accessToken: 'Bearer eyASKLFABADFJ',
refreshToken: 'KASDLNWE0JKH5KHK1K5JKH',
controlToken: 'Bearer eyASWAWJPLZL',
deviceId: 'aaaa-bbbb-cccc-eeee',
tokenExpiresAt: Date.now() / 1000,
controlTokenExpiresAt: 0,
};

// mock token request
(got as any).mockReturnValueOnce({
body: { controlToken: 'fake', controlTokenExpiresAt: 10000000 },
body: JSON.stringify({ access_token: 'AAAAAAAA', expires_in: 10 }),
statusCode: 200,
});

(got as any).mockClear();

const result = await vehicle.controller.refreshAccessToken();
expect(result).toEqual('Token refreshed');
// should update access token
expect(vehicle.controller.session.accessToken).toEqual('Bearer AAAAAAAA');
expect(vehicle.controller.session.tokenExpiresAt).toBeGreaterThan(Date.now() / 1000);
expect(vehicle.controller.session.tokenExpiresAt).toBeLessThan(Date.now() / 1000 + 20);

const gotArgs = (got as any).mock.calls[0];
expect(gotArgs[0]).toMatch(/token$/);
expect(gotArgs[1].body).toContain("grant_type=refresh_token");
expect(gotArgs[1].body).toContain("refresh_token=" + vehicle.controller.session.refreshToken);
});

it('not refresh active access token', async () => {
// create session with active access token
vehicle.controller.session = {
accessToken: 'Bearer eyASKLFABADFJ',
refreshToken: 'KASDLNWE0JKH5KHK1K5JKH',
controlToken: 'Bearer eyASWAWJPLZL',
deviceId: 'aaaa-bbbb-cccc-eeee',
tokenExpiresAt: Date.now() / 1000 + 20,
controlTokenExpiresAt: 0,
};

(got as any).mockClear();

const result = await vehicle.controller.refreshAccessToken();
expect(result).toEqual('Token not expired, no need to refresh');
// should not call got
expect((got as any).mock.calls).toHaveLength(0);
});

it('refresh expired control token', async () => {
// create session with active access token and expired control token
vehicle.controller.session = {
accessToken: 'Bearer eyASKLFABADFJ',
refreshToken: 'KASDLNWE0JKH5KHK1K5JKH',
controlToken: 'Bearer eyASWAWJPLZL',
deviceId: 'aaaa-bbbb-cccc-eeee',
tokenExpiresAt: Date.now() / 1000 + 20,
controlTokenExpiresAt: Date.now() / 1000 - 10,
};

// mock pin request
(got as any).mockReturnValueOnce({
body: { controlToken: 'BBBBBB', expiresTime: 10 },
statusCode: 200,
});

(got as any).mockClear();

await vehicle.checkControlToken();
// should update control token
expect(vehicle.controller.session.controlToken).toEqual('Bearer BBBBBB');
expect(vehicle.controller.session.controlTokenExpiresAt).toBeGreaterThan(Date.now() / 1000);
expect(vehicle.controller.session.controlTokenExpiresAt).toBeLessThan(Date.now() / 1000 + 20);

const gotArgs = (got as any).mock.calls[0];
expect(gotArgs[0]).toMatch(/pin$/);
expect(gotArgs[1].headers.Authorization).toEqual(vehicle.controller.session.accessToken);
expect(gotArgs[1].body.deviceId).toEqual("aaaa-bbbb-cccc-eeee");
expect(gotArgs[1].body.pin).toEqual("1234");
});

it('not refresh active control token', async () => {
// create session with active control and access token
vehicle.controller.session = {
accessToken: 'Bearer eyASKLFABADFJ',
refreshToken: 'KASDLNWE0JKH5KHK1K5JKH',
controlToken: 'Bearer eyASWAWJPLZL',
deviceId: 'aaaa-bbbb-cccc-eeee',
tokenExpiresAt: Date.now() / 1000 + 20,
controlTokenExpiresAt: Date.now() / 1000 + 10,
};

(got as any).mockClear();

await vehicle.checkControlToken();
// should not call got
expect((got as any).mock.calls).toHaveLength(0);
});

it('call status commmand', async () => {
// create session with active control and access token
vehicle.controller.session = {
accessToken: 'Bearer eyASKLFABADFJ',
refreshToken: 'KASDLNWE0JKH5KHK1K5JKH',
controlToken: 'Bearer eyASWAWJPLZL',
deviceId: 'aaaa-bbbb-cccc-eeee',
tokenExpiresAt: Date.now() / 1000 + 20,
controlTokenExpiresAt: Date.now() / 1000 + 10,
};

// mock the status request
(got as any).mockReturnValueOnce({
body: EUROPE_STATUS_MOCK,
Expand Down
8 changes: 5 additions & 3 deletions lib/constants/europe.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { CLIENT_ID } from './america';

export const EU_API_HOST = 'prd.eu-ccapi.hyundai.com:8080';
export const EU_BASE_URL = `https://${EU_API_HOST}`;

export const EU_CLIENT_ID = '6d477c38-3ca4-4cf3-9557-2a1929a94654';

export const EU_ENDPOINTS = {
session: `${EU_BASE_URL}/api/v1/user/oauth2/authorize?response_type=code&state=test&client_id=6d477c38-3ca4-4cf3-9557-2a1929a94654&redirect_uri=${EU_BASE_URL}/api/v1/user/oauth2/redirect`,
session: `${EU_BASE_URL}/api/v1/user/oauth2/authorize?response_type=code&state=test&client_id=${CLIENT_ID}&redirect_uri=${EU_BASE_URL}/api/v1/user/oauth2/redirect`,
login: `${EU_BASE_URL}/api/v1/user/signin`,
language: `${EU_BASE_URL}/api/v1/user/language`,
redirectUri: `${EU_BASE_URL}/api/v1/user/oauth2/redirect`,
Expand All @@ -14,5 +18,3 @@ export const EU_CONSTANTS = {
'Basic NmQ0NzdjMzgtM2NhNC00Y2YzLTk1NTctMmExOTI5YTk0NjU0OktVeTQ5WHhQekxwTHVvSzB4aEJDNzdXNlZYaG10UVI5aVFobUlGampvWTRJcHhzVg==',
GCMSenderID: '199360397125',
};

export const EU_CLIENT_ID = '6d477c38-3ca4-4cf3-9557-2a1929a94654';
1 change: 1 addition & 0 deletions lib/controllers/european.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ export class EuropeanController extends SessionController {
cookieJar,
});

logger.debug(authCodeResponse.body);
let authorizationCode;
if (authCodeResponse) {
const regexMatch = /code=([^&]*)/g.exec(authCodeResponse.body.redirectUrl);
Expand Down
33 changes: 31 additions & 2 deletions lib/vehicles/american.vehicle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ export default class AmericanVehicle extends Vehicle {
}

public async stop(): Promise<string> {
const response = await this._request(`${BASE_URL}/ac/v2/rcs/rsc/stop`, {
const response = await this._request(`/ac/v2/rcs/rsc/stop`, {
method: 'POST',
headers: {
...this.getDefaultHeaders(),
Expand Down Expand Up @@ -252,6 +252,35 @@ export default class AmericanVehicle extends Vehicle {
return 'Something went wrong!';
}

public async startCharge(): Promise<string> {
const response = await this._request(
`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/charge`,
{
method: 'POST',
}
);

if (response.statusCode === 200) {
logger.debug(`Send start charge command to Vehicle ${this.vehicleConfig.id}`);
return 'Start charge successful';
}

throw 'Something went wrong!';
}

public async stopCharge(): Promise<string> {
const response = await got(`/api/v2/spa/vehicles/${this.vehicleConfig.id}/control/charge`, {
method: 'POST',
});

if (response.statusCode === 200) {
logger.debug(`Send stop charge command to vehicle ${this.vehicleConfig.id}`);
return 'Stop charge successful';
}

throw 'Something went wrong!';
}

// TODO: not sure how to type a dynamic response
/* eslint-disable @typescript-eslint/no-explicit-any */
private async _request(service: string, options): Promise<got.Response<any>> {
Expand All @@ -266,7 +295,7 @@ export default class AmericanVehicle extends Vehicle {
logger.debug('Token is all good, moving on!');
}

const response = await got(`${BASE_URL}/${service}`, options);
const response = await got(`${BASE_URL}/${service}`, { throwHttpErrors: false, ...options });
logger.debug(response.body);

return response;
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bluelinky",
"version": "5.2.0",
"version": "5.2.1",
"description": "",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default {
format: 'cjs',
name: 'index',
file: 'dist/index.js',
banner: "/* @preserve skinview3d / MIT License / https://github.com/bs-community/skinview3d */",
banner: '/* @preserve bluelinky / MIT License / https://github.com/Hacksore/bluelinky */',
},
external: [...Object.keys(pkg.dependencies || {}), 'events'],
plugins: [
Expand Down

0 comments on commit f3051a5

Please sign in to comment.