Skip to content

Commit

Permalink
feat(client): get/set/delete cookies + domstorage
Browse files Browse the repository at this point in the history
# Conflicts:
#	client/package.json
#	core-interfaces/package.json
#	core/package.json
  • Loading branch information
blakebyrnes committed Nov 5, 2020
1 parent 3bd89e3 commit 2e2de6b
Show file tree
Hide file tree
Showing 36 changed files with 645 additions and 151 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/lint-and-test.yml
Expand Up @@ -74,7 +74,7 @@ jobs:

- uses: actions/setup-node@v1
with:
node-version: 12
node-version: ${{ matrix.node-version }}
- uses: actions/setup-go@v2
with:
go-version: 1.14
Expand Down
67 changes: 29 additions & 38 deletions client/index.ts
@@ -1,41 +1,37 @@
// setup must go first
import './lib/SetupAwaitedHandler';

import { ILocationTrigger, LocationStatus } from '@secret-agent/core-interfaces/Location';
import IConfigureOptions from '@secret-agent/core-interfaces/IConfigureOptions';
import { RenderingOption } from '@secret-agent/core-interfaces/ITabOptions';
import os from 'os';
import initializeConstantsAndProperties from 'awaited-dom/base/initializeConstantsAndProperties';
import { IRequestInit } from 'awaited-dom/base/interfaces/official';
import { ISuperElement } from 'awaited-dom/base/interfaces/super';
import { ICookie } from '@secret-agent/core-interfaces/ICookie';
import IDomStorage from '@secret-agent/core-interfaces/IDomStorage';
import ISessionOptions from '@secret-agent/core-interfaces/ISessionOptions';
import IUserProfile from '@secret-agent/core-interfaces/IUserProfile';
import IWaitForResourceOptions from '@secret-agent/core-interfaces/IWaitForResourceOptions';
import IWaitForElementOptions from '@secret-agent/core-interfaces/IWaitForElementOptions';
import StateMachine from 'awaited-dom/base/StateMachine';
import Request from 'awaited-dom/impl/official-klasses/Request';
import { bindFunctions } from '@secret-agent/commons/utils';
import ICreateSessionOptions from '@secret-agent/core-interfaces/ICreateSessionOptions';
import ICreateSecretAgentOptions from './interfaces/ICreateSecretAgentOptions';
import CoreClient from './lib/CoreClient';
import "./lib/SetupAwaitedHandler";

import { ILocationTrigger, LocationStatus } from "@secret-agent/core-interfaces/Location";
import IConfigureOptions from "@secret-agent/core-interfaces/IConfigureOptions";
import { RenderingOption } from "@secret-agent/core-interfaces/ITabOptions";
import os from "os";
import initializeConstantsAndProperties from "awaited-dom/base/initializeConstantsAndProperties";
import { IRequestInit } from "awaited-dom/base/interfaces/official";
import { ISuperElement } from "awaited-dom/base/interfaces/super";
import IDomStorage from "@secret-agent/core-interfaces/IDomStorage";
import ISessionOptions from "@secret-agent/core-interfaces/ISessionOptions";
import IUserProfile from "@secret-agent/core-interfaces/IUserProfile";
import IWaitForResourceOptions from "@secret-agent/core-interfaces/IWaitForResourceOptions";
import IWaitForElementOptions from "@secret-agent/core-interfaces/IWaitForElementOptions";
import StateMachine from "awaited-dom/base/StateMachine";
import Request from "awaited-dom/impl/official-klasses/Request";
import { bindFunctions } from "@secret-agent/commons/utils";
import ICreateSessionOptions from "@secret-agent/core-interfaces/ICreateSessionOptions";
import ICreateSecretAgentOptions from "./interfaces/ICreateSecretAgentOptions";
import CoreClient from "./lib/CoreClient";
import ISecretAgentClass, {
ISecretAgent,
ISecretAgentConfigureOptions, ISecretAgentEvents,
ISecretAgentConfigureOptions,
ISecretAgentEvents,
SecretAgentStatics
} from "./interfaces/ISecretAgent";
import CoreTab from './lib/CoreTab';
import Tab, { createTab, getCoreTab } from './lib/Tab';
import IInteractions, {
Command,
IMousePosition,
ITypeInteraction,
} from './interfaces/IInteractions';
import Interactor from './lib/Interactor';
import IWaitForResourceFilter from './interfaces/IWaitForResourceFilter';
import AwaitedEventTarget from './lib/AwaitedEventTarget';
import ScriptInstance from './lib/ScriptInstance';
import CoreTab from "./lib/CoreTab";
import Tab, { createTab, getCoreTab } from "./lib/Tab";
import IInteractions, { Command, IMousePosition, ITypeInteraction } from "./interfaces/IInteractions";
import Interactor from "./lib/Interactor";
import IWaitForResourceFilter from "./interfaces/IWaitForResourceFilter";
import AwaitedEventTarget from "./lib/AwaitedEventTarget";
import ScriptInstance from "./lib/ScriptInstance";
import Signals = NodeJS.Signals;

const DefaultOptions = {
Expand Down Expand Up @@ -64,7 +60,6 @@ export function SecretAgentClientGenerator(
'activeTab',
'sessionName',
'url',
'cookies',
'lastCommandId',
'Request',
];
Expand Down Expand Up @@ -125,10 +120,6 @@ export function SecretAgentClientGenerator(
return getState(this).activeTab;
}

public get cookies(): Promise<ICookie[]> {
return getCoreTab(this.activeTab).then(x => x.getAllCookies());
}

public get document() {
return this.activeTab.document;
}
Expand Down
38 changes: 18 additions & 20 deletions client/interfaces/ISecretAgent.ts
@@ -1,22 +1,21 @@
import IConfigureOptions from '@secret-agent/core-interfaces/IConfigureOptions';
import { IRenderingOption } from '@secret-agent/core-interfaces/ITabOptions';
import IUserProfile from '@secret-agent/core-interfaces/IUserProfile';
import SuperDocument from 'awaited-dom/impl/super-klasses/SuperDocument';
import { ILocationTrigger } from '@secret-agent/core-interfaces/Location';
import ISessionOptions from '@secret-agent/core-interfaces/ISessionOptions';
import { ISuperElement } from 'awaited-dom/base/interfaces/super';
import IWaitForResourceOptions from '@secret-agent/core-interfaces/IWaitForResourceOptions';
import Response from 'awaited-dom/impl/official-klasses/Response';
import { IRequestInit } from 'awaited-dom/base/interfaces/official';
import Request from 'awaited-dom/impl/official-klasses/Request';
import { ICookie } from '@secret-agent/core-interfaces/ICookie';
import IWaitForElementOptions from '@secret-agent/core-interfaces/IWaitForElementOptions';
import Resource from '../lib/Resource';
import IInteractions, { IMousePosition, ITypeInteraction } from './IInteractions';
import IWaitForResourceFilter from './IWaitForResourceFilter';
import ICreateSecretAgentOptions from './ICreateSecretAgentOptions';
import Tab from '../lib/Tab';
import IAwaitedEventTarget from './IAwaitedEventTarget';
import IConfigureOptions from "@secret-agent/core-interfaces/IConfigureOptions";
import { IRenderingOption } from "@secret-agent/core-interfaces/ITabOptions";
import IUserProfile from "@secret-agent/core-interfaces/IUserProfile";
import SuperDocument from "awaited-dom/impl/super-klasses/SuperDocument";
import { ILocationTrigger } from "@secret-agent/core-interfaces/Location";
import ISessionOptions from "@secret-agent/core-interfaces/ISessionOptions";
import { ISuperElement } from "awaited-dom/base/interfaces/super";
import IWaitForResourceOptions from "@secret-agent/core-interfaces/IWaitForResourceOptions";
import Response from "awaited-dom/impl/official-klasses/Response";
import { IRequestInit } from "awaited-dom/base/interfaces/official";
import Request from "awaited-dom/impl/official-klasses/Request";
import IWaitForElementOptions from "@secret-agent/core-interfaces/IWaitForElementOptions";
import Resource from "../lib/Resource";
import IInteractions, { IMousePosition, ITypeInteraction } from "./IInteractions";
import IWaitForResourceFilter from "./IWaitForResourceFilter";
import ICreateSecretAgentOptions from "./ICreateSecretAgentOptions";
import Tab from "../lib/Tab";
import IAwaitedEventTarget from "./IAwaitedEventTarget";

export interface ISecretAgentConfigureOptions extends IConfigureOptions {
defaultRenderingOptions: IRenderingOption[];
Expand All @@ -39,7 +38,6 @@ export interface ISecretAgent extends IAwaitedEventTarget<ISecretAgentEvents> {
activeTab: Tab;
sessionName: Promise<string>;
url: Promise<string>;
cookies: Promise<ICookie[]>;
lastCommandId: Promise<number>;

click(mousePosition: IMousePosition): Promise<void>;
Expand Down
59 changes: 59 additions & 0 deletions client/lib/CookieStorage.ts
@@ -0,0 +1,59 @@
import initializeConstantsAndProperties from 'awaited-dom/base/initializeConstantsAndProperties';
import StateMachine from 'awaited-dom/base/StateMachine';
import ISetCookieOptions from '@secret-agent/core-interfaces/ISetCookieOptions';
import CoreTab from './CoreTab';

const { getState, setState } = StateMachine<CookieStorage, IState>();

interface IState {
coreTab: Promise<CoreTab>;
}

export default class CookieStorage {
constructor() {
initializeConstantsAndProperties(this, [], []);
}

public get length() {
return this.getItems().then(x => x.length);
}

public async getItems() {
const coreTab = await getState(this).coreTab;
return await coreTab.getCookies();
}

public async key(index: number) {
const cookies = await this.getItems();
return Object.keys(cookies)[index];
}

public async clear() {
const coreTab = await getState(this).coreTab;
const cookies = await this.getItems();
for (const cookie of cookies) {
await coreTab.removeCookie(cookie.name);
}
}

public async getItem(key: string) {
const cookies = await this.getItems();
return cookies.find(x => x.name === key);
}

public async setItem(key: string, value: string, options?: ISetCookieOptions) {
const coreTab = await getState(this).coreTab;
return coreTab.setCookie(key, value, options);
}

public async removeItem(name: string) {
const coreTab = await getState(this).coreTab;
return coreTab.removeCookie(name);
}
}

export function createCookieStorage(coreTab: Promise<CoreTab>) {
const cookieStorage = new CookieStorage();
setState(cookieStorage, { coreTab });
return cookieStorage;
}
17 changes: 13 additions & 4 deletions client/lib/CoreTab.ts
Expand Up @@ -11,6 +11,7 @@ import IUserProfile from '@secret-agent/core-interfaces/IUserProfile';
import IExecJsPathResult from '@secret-agent/core/interfaces/IExecJsPathResult';
import { IRequestInit } from 'awaited-dom/base/interfaces/official';
import IAttachedState from 'awaited-dom/base/IAttachedState';
import ISetCookieOptions from '@secret-agent/core-interfaces/ISetCookieOptions';
import CoreClient from './CoreClient';
import CoreCommandQueue from './CoreCommandQueue';
import CoreEventHeap from './CoreEventHeap';
Expand Down Expand Up @@ -98,12 +99,20 @@ export default class CoreTab {
return await this.commandQueue.run('exportUserProfile');
}

public async getPageCookies(): Promise<ICookie[]> {
return await this.commandQueue.run('getPageCookies');
public async getCookies(): Promise<ICookie[]> {
return await this.commandQueue.run('getTabCookies');
}

public async getAllCookies(): Promise<ICookie[]> {
return await this.commandQueue.run('getUserCookies');
public async setCookie(
name: string,
value: string,
options?: ISetCookieOptions,
): Promise<boolean> {
return await this.commandQueue.run('setTabCookie', name, value, options);
}

public async removeCookie(name: string): Promise<boolean> {
return await this.commandQueue.run('removeTabCookie', name);
}

public async isElementVisible(jsPath: IJsPath): Promise<boolean> {
Expand Down
25 changes: 20 additions & 5 deletions client/lib/Tab.ts
@@ -1,11 +1,11 @@
import initializeConstantsAndProperties from 'awaited-dom/base/initializeConstantsAndProperties';
import StateMachine from 'awaited-dom/base/StateMachine';
import { ICookie } from '@secret-agent/core-interfaces/ICookie';
import { ISuperElement } from 'awaited-dom/base/interfaces/super';
import AwaitedPath from 'awaited-dom/base/AwaitedPath';
import { IRequestInit } from 'awaited-dom/base/interfaces/official';
import SuperDocument from 'awaited-dom/impl/super-klasses/SuperDocument';
import { createResponse, createSuperDocument } from 'awaited-dom/impl/create';
import Storage from 'awaited-dom/impl/official-klasses/Storage';
import { createResponse, createStorage, createSuperDocument } from 'awaited-dom/impl/create';
import Request from 'awaited-dom/impl/official-klasses/Request';
import { ILocationTrigger, LocationStatus } from '@secret-agent/core-interfaces/Location';
import IWaitForResourceOptions from '@secret-agent/core-interfaces/IWaitForResourceOptions';
Expand All @@ -18,6 +18,7 @@ import IAwaitedOptions from '../interfaces/IAwaitedOptions';
import RequestGenerator, { getRequestIdOrUrl } from './Request';
import AwaitedEventTarget from './AwaitedEventTarget';
import { ISecretAgent } from '../interfaces/ISecretAgent';
import CookieStorage, { createCookieStorage } from './CookieStorage';

const { getState, setState } = StateMachine<Tab, IState>();
const agentState = StateMachine<ISecretAgent, { activeTab: Tab; tabs: Tab[] }>();
Expand All @@ -36,7 +37,9 @@ const propertyKeys: (keyof Tab)[] = [
'lastCommandId',
'tabId',
'url',
'cookies',
'cookieStorage',
'localStorage',
'sessionStorage',
'document',
'Request',
];
Expand All @@ -63,8 +66,8 @@ export default class Tab extends AwaitedEventTarget<IEventType, IState> {
return getCoreTab(this).then(x => x.getUrl());
}

public get cookies(): Promise<ICookie[]> {
return getCoreTab(this).then(x => x.getPageCookies());
public get cookieStorage(): CookieStorage {
return createCookieStorage(getCoreTab(this));
}

public get document(): SuperDocument {
Expand All @@ -73,6 +76,18 @@ export default class Tab extends AwaitedEventTarget<IEventType, IState> {
return createSuperDocument<IAwaitedOptions>(awaitedPath, awaitedOptions) as SuperDocument;
}

public get localStorage(): Storage {
const awaitedPath = new AwaitedPath('localStorage');
const awaitedOptions = { ...getState(this) };
return createStorage<IAwaitedOptions>(awaitedPath, awaitedOptions) as Storage;
}

public get sessionStorage(): Storage {
const awaitedPath = new AwaitedPath('sessionStorage');
const awaitedOptions = { ...getState(this) };
return createStorage<IAwaitedOptions>(awaitedPath, awaitedOptions) as Storage;
}

public get Request(): typeof Request {
return RequestGenerator(getCoreTab(this));
}
Expand Down
2 changes: 1 addition & 1 deletion client/package.json
Expand Up @@ -7,7 +7,7 @@
"@secret-agent/core": "1.1.0-alpha.0",
"@secret-agent/core-interfaces": "1.1.0-alpha.0",
"@secret-agent/replay": "1.1.0-alpha.0",
"awaited-dom": "^1.1.5",
"awaited-dom": "^1.1.6",
"uuid": "^8.1.0"
},
"devDependencies": {
Expand Down
4 changes: 2 additions & 2 deletions client/test/basic.test.ts
@@ -1,4 +1,4 @@
import { SecretAgentClientGenerator } from '../index';
import { SecretAgentClientGenerator } from "../index";

describe('basic SecretAgent tests', () => {
it('starts, configures, and shuts down', async () => {
Expand Down Expand Up @@ -32,7 +32,7 @@ describe('basic SecretAgent tests', () => {
}
});

const agent = await new SecretAgent();
await new SecretAgent();
await SecretAgent.shutdown();

const outgoingCommands = (coreClient.pipeOutgoingCommand as any).mock.calls;
Expand Down
6 changes: 6 additions & 0 deletions core-interfaces/ISetCookieOptions.ts
@@ -0,0 +1,6 @@
import { ICookie } from './ICookie';

export default interface ISetCookieOptions
extends Pick<ICookie, 'httpOnly' | 'secure' | 'sameSite'> {
expires?: Date | number;
}
2 changes: 1 addition & 1 deletion core-interfaces/package.json
Expand Up @@ -4,7 +4,7 @@
"description": "Core interfaces used by SecretAgent",
"dependencies": {
"@secret-agent/commons": "1.1.0-alpha.0",
"awaited-dom": "^1.1.5"
"awaited-dom": "^1.1.6"
},
"devDependencies": {
"@secret-agent/injected-scripts": "1.1.0-alpha.0",
Expand Down
27 changes: 21 additions & 6 deletions core/index.ts
Expand Up @@ -23,6 +23,7 @@ import Queue from '@secret-agent/commons/Queue';
import Chrome83 from '@secret-agent/emulate-chrome-83';
import Emulators from '@secret-agent/emulators';
import IResourceMeta from '@secret-agent/core-interfaces/IResourceMeta';
import ISetCookieOptions from '@secret-agent/core-interfaces/ISetCookieOptions';
import IListenerObject from './interfaces/IListenerObject';
import UserProfile from './lib/UserProfile';
import Session from './lib/Session';
Expand Down Expand Up @@ -119,12 +120,20 @@ export default class Core implements ICore {
await this.tab.runCommand('interact', interactionGroups);
}

public async getPageCookies() {
return await this.tab.runCommand('getPageCookies');
public async getTabCookies() {
return await this.tab.runCommand('getCookies');
}

public async getUserCookies() {
return await this.tab.runCommand('getUserCookies');
public async setTabCookie(
name: string,
value: string,
options?: ISetCookieOptions,
): Promise<boolean> {
return await this.tab.runCommand('setCookie', name, value, options);
}

public async removeTabCookie(name: string): Promise<boolean> {
return await this.tab.runCommand('removeCookie', name);
}

public async exportUserProfile() {
Expand Down Expand Up @@ -270,8 +279,14 @@ export default class Core implements ICore {
}

public static async configure(options: IConfigureOptions) {
const { maxConcurrentSessionsCount, localProxyPortStart, sessionsDir, activeEmulatorIds } = options;
if (maxConcurrentSessionsCount) GlobalPool.maxConcurrentSessionsCount = options.maxConcurrentSessionsCount;
const {
maxConcurrentSessionsCount,
localProxyPortStart,
sessionsDir,
activeEmulatorIds,
} = options;
if (maxConcurrentSessionsCount)
GlobalPool.maxConcurrentSessionsCount = options.maxConcurrentSessionsCount;
if (localProxyPortStart) GlobalPool.localProxyPortStart = options.localProxyPortStart;
if (sessionsDir) GlobalPool.sessionsDir = options.sessionsDir;
if (activeEmulatorIds?.length) await GlobalPool.start(activeEmulatorIds);
Expand Down

0 comments on commit 2e2de6b

Please sign in to comment.