Skip to content

Commit 3e87a4c

Browse files
committed
Implements Opting Into Auto Trading along with Sending Cookies
1 parent c0b3676 commit 3e87a4c

File tree

10 files changed

+213
-78
lines changed

10 files changed

+213
-78
lines changed

manifest.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,7 @@
4444
"type": "module"
4545
},
4646
"permissions": ["storage", "scripting"],
47-
"optional_permissions": ["cookies"],
48-
"optional_host_permissions": ["https://steamcommunity.com/"],
47+
"optional_permissions": ["cookies", "alarms"],
4948
"host_permissions": [
5049
"*://*.steamcommunity.com/market/listings/730/*",
5150
"*://*.steamcommunity.com/id/*/inventory*",

src/background.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,17 @@ function unifiedHandler(request: any, sender: MessageSender, sendResponse: (resp
2020
});
2121
}
2222

23+
function requestPermissions(permissions: string[], sendResponse: any) {
24+
chrome.permissions.request({permissions}, (granted) => sendResponse(granted));
25+
26+
return true;
27+
}
28+
2329
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
30+
if (request.message === 'requestPermissions') {
31+
return requestPermissions(request.permissions, sendResponse);
32+
}
33+
2434
unifiedHandler(request, sender, sendResponse);
2535
return true;
2636
});

src/lib/bridge/client.ts

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {InternalRequestBundle, InternalResponseBundle, RequestHandler, Version}
22
import {isFirefox, runtimeNamespace} from '../utils/detect';
33
import {inPageContext} from '../utils/snips';
44
import {g_PostMessageBus} from '../bus/post_message_bus';
5+
import {DeferredPromise} from '../utils/deferred_promise';
56

67
function canUseSendMessage() {
78
// Not supported in Firefox Page Context
@@ -22,21 +23,23 @@ export async function ClientSend<Req, Resp>(handler: RequestHandler<Req, Resp>,
2223
};
2324

2425
if (canUseSendMessage()) {
25-
return new Promise((resolve, reject) => {
26+
const promise = new DeferredPromise<Resp>();
27+
28+
// @ts-ignore Bad types
29+
runtimeNamespace().runtime.sendMessage(
30+
window.CSFLOAT_EXTENSION_ID || chrome.runtime.id,
31+
bundle,
2632
// @ts-ignore Bad types
27-
runtimeNamespace().runtime.sendMessage(
28-
window.CSFLOAT_EXTENSION_ID || chrome.runtime.id,
29-
bundle,
30-
// @ts-ignore Bad types
31-
(resp: InternalResponseBundle) => {
32-
if (resp?.response) {
33-
resolve(resp.response);
34-
} else {
35-
reject(resp?.error);
36-
}
33+
(resp: InternalResponseBundle) => {
34+
if (resp?.response) {
35+
promise.resolve(resp.response);
36+
} else {
37+
promise.reject(resp?.error);
3738
}
38-
);
39-
});
39+
}
40+
);
41+
42+
return promise.promise();
4043
} else {
4144
// Fallback to postmessage bus for browsers that don't implement
4245
// specs fully

src/lib/bridge/handlers/handlers.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {FetchExtensionFile} from './fetch_extension_file';
1313
import {AnnotateOffer} from './annotate_offer';
1414
import {ExtensionVersion} from './extension_version';
1515
import {SendCookies} from './send_cookies';
16+
import {HasPermissions} from './has_permissions';
1617

1718
export const HANDLERS_MAP: {[key in RequestType]: RequestHandler<any, any>} = {
1819
[RequestType.EXECUTE_SCRIPT_ON_PAGE]: ExecuteScriptOnPage,
@@ -28,4 +29,5 @@ export const HANDLERS_MAP: {[key in RequestType]: RequestHandler<any, any>} = {
2829
[RequestType.ANNOTATE_OFFER]: AnnotateOffer,
2930
[RequestType.EXTENSION_VERSION]: ExtensionVersion,
3031
[RequestType.SEND_COOKIES]: SendCookies,
32+
[RequestType.HAS_PERMISSIONS]: HasPermissions,
3133
};
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import {SimpleHandler} from './main';
2+
import {RequestType} from './types';
3+
4+
export interface HasPermissionsRequest {
5+
permissions: string[];
6+
}
7+
8+
export interface HasPermissionsResponse {
9+
granted: boolean;
10+
}
11+
12+
export const HasPermissions = new SimpleHandler<HasPermissionsRequest, HasPermissionsResponse>(
13+
RequestType.HAS_PERMISSIONS,
14+
async (req) => {
15+
// @ts-ignore
16+
const granted = (await chrome.permissions.contains({
17+
permissions: req.permissions,
18+
})) as boolean;
19+
20+
return {
21+
granted,
22+
};
23+
}
24+
);
Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,48 @@
11
import {SimpleHandler} from './main';
22
import {RequestType} from './types';
33

4-
export interface SendCookiesRequest {
5-
verify_only?: boolean;
6-
}
4+
export interface SendCookiesRequest {}
75

86
export interface SendCookiesResponse {}
97

108
export const SendCookies = new SimpleHandler<SendCookiesRequest, SendCookiesResponse>(
119
RequestType.SEND_COOKIES,
1210
async (req) => {
13-
console.log('cookies 123');
14-
// @ts-ignore MV3 returns a promise
15-
const hasPermission = (await chrome.permissions.contains({
16-
permissions: ['cookies'],
17-
origins: ['https://steamcommunity.com/'],
18-
})) as boolean;
19-
20-
console.log(hasPermission);
21-
22-
if (!hasPermission) {
23-
// @ts-ignore MV3 returns a promise
24-
const granted = (await chrome.permissions.request({
25-
permissions: ['cookies'],
26-
origins: ['https://steamcommunity.com/'],
27-
})) as boolean;
28-
if (!granted) {
29-
throw new Error('failed to grant permission, cannot proceed');
30-
}
31-
}
32-
33-
if (req.verify_only) {
34-
return {} as SendCookiesResponse;
35-
}
36-
3711
const cookies = await chrome.cookies.getAll({
3812
domain: 'steamcommunity.com',
3913
});
4014

41-
console.log(cookies);
15+
// For use in verifying trades on CSFloat, opt-in
16+
const formatted = cookies
17+
.filter((e) => {
18+
return [
19+
'timezoneOffset',
20+
'Steam_Language',
21+
'browserid',
22+
'sessionid',
23+
'steamCountry',
24+
'steamLoginSecure',
25+
].includes(e.name);
26+
})
27+
.map((e) => {
28+
return {
29+
name: e.name,
30+
value: e.value,
31+
expiration: e.expirationDate,
32+
};
33+
});
34+
35+
const resp = await fetch(`https://csfloat.com/api/v1/me/steam-cookies`, {
36+
credentials: 'include',
37+
method: 'POST',
38+
headers: {
39+
'Content-Type': 'application/json',
40+
},
41+
body: JSON.stringify({
42+
cookies: formatted,
43+
}),
44+
});
4245

4346
return {} as SendCookiesResponse;
44-
// const resp = await fetch(`https://csfloat.com/api/v1/me/steam-cookies`, {
45-
// credentials: 'include',
46-
// method: 'POST',
47-
// headers: {
48-
// 'Content-Type': 'application/json',
49-
// },
50-
// body: JSON.stringify(req),
51-
// });
5247
}
5348
);

src/lib/bridge/handlers/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ export enum RequestType {
1212
ANNOTATE_OFFER,
1313
EXTENSION_VERSION,
1414
SEND_COOKIES,
15+
HAS_PERMISSIONS,
1516
}

src/lib/components/trade_offer/auto_fill.ts

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {Observe} from '../../utils/observers';
99

1010
import '../common/ui/steam-button';
1111
import {AppId, ContextId} from '../../types/steam_constants';
12-
import {SendCookies} from '../../bridge/handlers/send_cookies';
1312

1413
@CustomElement()
1514
@InjectBefore('div.trade_area')
@@ -106,31 +105,6 @@ export class AutoFill extends FloatElement {
106105
`;
107106
}
108107

109-
renderAutoManageTradeOffers() {
110-
return html`
111-
<div class="container" style="margin: 20px 0 20px 0;">
112-
<div>
113-
<div class="float-icon">
114-
<img
115-
src="https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/79/798a12316637ad8fbb91ddb7dc63f770b680bd19_full.jpg"
116-
style="height: 32px;"
117-
/>
118-
</div>
119-
<span class="item-name"> Automatically Create Offers </span>
120-
<div class="sale-info">Allow CSFloat to automatically track and create offers.</div>
121-
</div>
122-
<csfloat-steam-button
123-
.text="${'Enable Auto Trading'}"
124-
@click="${() => this.enableAutoTrading()}"
125-
></csfloat-steam-button>
126-
</div>
127-
`;
128-
}
129-
130-
async enableAutoTrading() {
131-
await ClientSend(SendCookies, {});
132-
}
133-
134108
renderBulkAutoFillDialog(rawTrades: Trade[]): HTMLTemplateResult {
135109
// Remove items already included and non-pending
136110
const fTrades = rawTrades
@@ -224,7 +198,7 @@ export class AutoFill extends FloatElement {
224198

225199
return html`
226200
${this.renderBulkAutoFillDialog(tradesToBuyer)} ${tradesToBuyer.map((e) => this.renderAutoFillDialog(e))}
227-
${this.showWarningDialog()} ${this.renderAutoManageTradeOffers()}
201+
${this.showWarningDialog()}
228202
`;
229203
}
230204

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import {css, html} from 'lit';
2+
3+
import {CustomElement, InjectAfter, InjectionMode} from '../injectors';
4+
import {FloatElement} from '../custom';
5+
import '../common/ui/steam-button';
6+
import {ClientSend} from '../../bridge/client';
7+
import {SendCookies} from '../../bridge/handlers/send_cookies';
8+
import {state} from 'lit/decorators.js';
9+
import {FetchPendingTrades} from '../../bridge/handlers/fetch_pending_trades';
10+
import {HasPermissions} from '../../bridge/handlers/has_permissions';
11+
12+
@CustomElement()
13+
@InjectAfter('.maincontent .profile_leftcol .nonresponsive_hidden', InjectionMode.ONCE)
14+
export class AutoTrackWidget extends FloatElement {
15+
@state()
16+
show = false;
17+
18+
static styles = [
19+
...FloatElement.styles,
20+
css`
21+
.container {
22+
margin-top: 10px;
23+
margin-bottom: 10px;
24+
padding: 15px;
25+
background-color: rgb(48, 48, 48);
26+
color: white;
27+
display: flex;
28+
justify-content: space-between;
29+
align-items: center;
30+
}
31+
32+
.container.warning {
33+
background-color: rgb(179, 0, 0);
34+
}
35+
36+
.float-icon {
37+
float: left;
38+
}
39+
40+
.item-name {
41+
font-size: 18px;
42+
margin-left: 15px;
43+
line-height: 32px;
44+
}
45+
46+
.sale-info {
47+
padding-left: 45px;
48+
color: darkgrey;
49+
}
50+
`,
51+
];
52+
53+
async connectedCallback() {
54+
super.connectedCallback();
55+
56+
try {
57+
await ClientSend(FetchPendingTrades, {});
58+
59+
const hasPermissions = await ClientSend(HasPermissions, {permissions: ['cookies', 'alarms']});
60+
if (!hasPermissions) {
61+
this.show = true;
62+
}
63+
} catch (e) {
64+
console.info('user is not logged into CSFloat');
65+
}
66+
}
67+
68+
render() {
69+
return this.show
70+
? html`
71+
<div class="container" style="margin: 20px 0 20px 0;">
72+
<div>
73+
<div class="float-icon">
74+
<img
75+
src="https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/79/798a12316637ad8fbb91ddb7dc63f770b680bd19_full.jpg"
76+
style="height: 32px;"
77+
/>
78+
</div>
79+
<span class="item-name"> Automatically Track Offers </span>
80+
<div class="sale-info">Allow CSFloat Market to automatically track and create offers.</div>
81+
</div>
82+
<csfloat-steam-button
83+
id="csfloat-enable-tracking"
84+
.text="${'Enable Tracking'}"
85+
></csfloat-steam-button>
86+
</div>
87+
`
88+
: html``;
89+
}
90+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,43 @@
11
import {init} from './utils';
22
import '../components/trade_offers/offer_id';
3+
import '../components/trade_offers/auto_track';
4+
import {inPageContext} from '../utils/snips';
5+
import {ClientSend} from '../bridge/client';
6+
import {SendCookies} from '../bridge/handlers/send_cookies';
37

48
init('src/lib/page_scripts/trade_offers.js', main);
59

610
function main() {}
11+
12+
if (!inPageContext()) {
13+
const refresh = setInterval(() => {
14+
const widget = document.getElementsByTagName('csfloat-auto-track-widget');
15+
if (!widget || widget.length === 0) {
16+
return;
17+
}
18+
19+
const btn = widget[0]?.shadowRoot?.getElementById('csfloat-enable-tracking');
20+
if (!btn) {
21+
return;
22+
}
23+
24+
btn.addEventListener('click', async () => {
25+
chrome.runtime.sendMessage(
26+
{
27+
message: 'requestPermissions',
28+
permissions: ['cookies', 'alarms'],
29+
},
30+
(granted) => {
31+
if (granted) {
32+
ClientSend(SendCookies, {});
33+
widget[0].parentElement?.removeChild(widget[0]);
34+
} else {
35+
alert('Failed to obtain permissions');
36+
}
37+
}
38+
);
39+
});
40+
41+
clearInterval(refresh);
42+
}, 500);
43+
}

0 commit comments

Comments
 (0)