opensoma 0.2.0 → 0.3.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/dist/package.json +2 -2
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +2 -1
- package/dist/src/cli.js.map +1 -1
- package/dist/src/client.d.ts +26 -1
- package/dist/src/client.d.ts.map +1 -1
- package/dist/src/client.js +141 -3
- package/dist/src/client.js.map +1 -1
- package/dist/src/commands/auth.d.ts +12 -0
- package/dist/src/commands/auth.d.ts.map +1 -1
- package/dist/src/commands/auth.js +151 -23
- package/dist/src/commands/auth.js.map +1 -1
- package/dist/src/commands/helpers.d.ts +12 -0
- package/dist/src/commands/helpers.d.ts.map +1 -1
- package/dist/src/commands/helpers.js +55 -9
- package/dist/src/commands/helpers.js.map +1 -1
- package/dist/src/commands/index.d.ts +1 -0
- package/dist/src/commands/index.d.ts.map +1 -1
- package/dist/src/commands/index.js +1 -0
- package/dist/src/commands/index.js.map +1 -1
- package/dist/src/commands/mentoring.d.ts.map +1 -1
- package/dist/src/commands/mentoring.js +37 -1
- package/dist/src/commands/mentoring.js.map +1 -1
- package/dist/src/commands/report.d.ts +27 -0
- package/dist/src/commands/report.d.ts.map +1 -0
- package/dist/src/commands/report.js +224 -0
- package/dist/src/commands/report.js.map +1 -0
- package/dist/src/constants.d.ts +2 -0
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +2 -0
- package/dist/src/constants.js.map +1 -1
- package/dist/src/credential-manager.d.ts +7 -0
- package/dist/src/credential-manager.d.ts.map +1 -1
- package/dist/src/credential-manager.js +76 -2
- package/dist/src/credential-manager.js.map +1 -1
- package/dist/src/formatters.d.ts +4 -1
- package/dist/src/formatters.d.ts.map +1 -1
- package/dist/src/formatters.js +91 -1
- package/dist/src/formatters.js.map +1 -1
- package/dist/src/http.d.ts +3 -0
- package/dist/src/http.d.ts.map +1 -1
- package/dist/src/http.js +109 -4
- package/dist/src/http.js.map +1 -1
- package/dist/src/session-recovery.d.ts +12 -0
- package/dist/src/session-recovery.d.ts.map +1 -0
- package/dist/src/session-recovery.js +34 -0
- package/dist/src/session-recovery.js.map +1 -0
- package/dist/src/shared/utils/report-params.d.ts +11 -0
- package/dist/src/shared/utils/report-params.d.ts.map +1 -0
- package/dist/src/shared/utils/report-params.js +27 -0
- package/dist/src/shared/utils/report-params.js.map +1 -0
- package/dist/src/shared/utils/swmaestro.d.ts +24 -0
- package/dist/src/shared/utils/swmaestro.d.ts.map +1 -1
- package/dist/src/shared/utils/swmaestro.js +50 -2
- package/dist/src/shared/utils/swmaestro.js.map +1 -1
- package/dist/src/token-extractor.d.ts.map +1 -1
- package/dist/src/token-extractor.js +38 -8
- package/dist/src/token-extractor.js.map +1 -1
- package/dist/src/types.d.ts +121 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js +72 -0
- package/dist/src/types.js.map +1 -1
- package/package.json +2 -2
- package/src/cli.ts +2 -0
- package/src/client.test.ts +95 -6
- package/src/client.ts +172 -4
- package/src/commands/auth.test.ts +152 -1
- package/src/commands/auth.ts +174 -28
- package/src/commands/helpers.test.ts +216 -0
- package/src/commands/helpers.ts +77 -12
- package/src/commands/index.ts +1 -0
- package/src/commands/mentoring.ts +55 -0
- package/src/commands/report.test.ts +49 -0
- package/src/commands/report.ts +322 -0
- package/src/constants.ts +2 -0
- package/src/credential-manager.test.ts +41 -1
- package/src/credential-manager.ts +103 -2
- package/src/formatters.test.ts +287 -0
- package/src/formatters.ts +105 -0
- package/src/http.test.ts +190 -4
- package/src/http.ts +132 -4
- package/src/session-recovery.ts +56 -0
- package/src/shared/utils/report-params.ts +41 -0
- package/src/shared/utils/swmaestro.ts +77 -5
- package/src/token-extractor.ts +59 -20
- package/src/types.test.ts +97 -0
- package/src/types.ts +84 -0
package/src/token-extractor.ts
CHANGED
|
@@ -22,9 +22,9 @@ type BrowserConfig = {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
type CookieRow = {
|
|
25
|
-
encrypted_value: Uint8Array | Buffer | null
|
|
25
|
+
encrypted_value: ArrayBuffer | Uint8Array | Buffer | null
|
|
26
26
|
last_access_utc?: number | bigint | null
|
|
27
|
-
value: string | null
|
|
27
|
+
value: ArrayBuffer | Uint8Array | Buffer | string | null
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
export interface ExtractedSessionCandidate {
|
|
@@ -92,6 +92,20 @@ function queryCookieDb(dbPath: string): CookieRow | undefined {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
try {
|
|
95
|
+
const Database = require('better-sqlite3') as new (
|
|
96
|
+
path: string,
|
|
97
|
+
options?: { readonly?: boolean },
|
|
98
|
+
) => {
|
|
99
|
+
close: () => void
|
|
100
|
+
prepare: (query: string) => { get: () => CookieRow | undefined }
|
|
101
|
+
}
|
|
102
|
+
const db = new Database(dbPath, { readonly: true })
|
|
103
|
+
try {
|
|
104
|
+
return db.prepare(COOKIE_QUERY).get() ?? undefined
|
|
105
|
+
} finally {
|
|
106
|
+
db.close()
|
|
107
|
+
}
|
|
108
|
+
} catch {
|
|
95
109
|
const { DatabaseSync } = require('node:sqlite') as {
|
|
96
110
|
DatabaseSync: new (
|
|
97
111
|
path: string,
|
|
@@ -107,20 +121,6 @@ function queryCookieDb(dbPath: string): CookieRow | undefined {
|
|
|
107
121
|
} finally {
|
|
108
122
|
db.close()
|
|
109
123
|
}
|
|
110
|
-
} catch {
|
|
111
|
-
const Database = require('better-sqlite3') as new (
|
|
112
|
-
path: string,
|
|
113
|
-
options?: { readonly?: boolean },
|
|
114
|
-
) => {
|
|
115
|
-
close: () => void
|
|
116
|
-
prepare: (query: string) => { get: () => CookieRow | undefined }
|
|
117
|
-
}
|
|
118
|
-
const db = new Database(dbPath, { readonly: true })
|
|
119
|
-
try {
|
|
120
|
-
return db.prepare(COOKIE_QUERY).get() ?? undefined
|
|
121
|
-
} finally {
|
|
122
|
-
db.close()
|
|
123
|
-
}
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
|
|
@@ -156,14 +156,14 @@ export class TokenExtractor {
|
|
|
156
156
|
const tempDatabasePath = join(tempDirectory, 'Cookies')
|
|
157
157
|
|
|
158
158
|
try {
|
|
159
|
-
|
|
159
|
+
copySqliteDatabase(databasePath, tempDatabasePath)
|
|
160
160
|
|
|
161
161
|
const row = queryCookieDb(tempDatabasePath)
|
|
162
162
|
if (!row) {
|
|
163
163
|
continue
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
-
const plaintextValue =
|
|
166
|
+
const plaintextValue = normalizeCookieText(row.value)
|
|
167
167
|
if (plaintextValue) {
|
|
168
168
|
this.addCandidate(candidates, {
|
|
169
169
|
browser: browser.name,
|
|
@@ -174,11 +174,12 @@ export class TokenExtractor {
|
|
|
174
174
|
continue
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
-
|
|
177
|
+
const encryptedValue = normalizeCookieBytes(row.encrypted_value)
|
|
178
|
+
if (!encryptedValue || encryptedValue.length === 0) {
|
|
178
179
|
continue
|
|
179
180
|
}
|
|
180
181
|
|
|
181
|
-
const decryptedValue = await this.decryptCookie(
|
|
182
|
+
const decryptedValue = await this.decryptCookie(encryptedValue, browser.name)
|
|
182
183
|
if (decryptedValue) {
|
|
183
184
|
this.addCandidate(candidates, {
|
|
184
185
|
browser: browser.name,
|
|
@@ -299,3 +300,41 @@ export class TokenExtractor {
|
|
|
299
300
|
return typeof lastAccessUtc === 'number' ? lastAccessUtc : 0
|
|
300
301
|
}
|
|
301
302
|
}
|
|
303
|
+
|
|
304
|
+
function copySqliteDatabase(sourcePath: string, targetPath: string): void {
|
|
305
|
+
copyFileSync(sourcePath, targetPath)
|
|
306
|
+
|
|
307
|
+
for (const suffix of ['-wal', '-shm']) {
|
|
308
|
+
const sidecarSourcePath = `${sourcePath}${suffix}`
|
|
309
|
+
if (!existsSync(sidecarSourcePath)) {
|
|
310
|
+
continue
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
copyFileSync(sidecarSourcePath, `${targetPath}${suffix}`)
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function normalizeCookieBytes(value: ArrayBuffer | Uint8Array | Buffer | null): Buffer | null {
|
|
318
|
+
if (!value) {
|
|
319
|
+
return null
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (Buffer.isBuffer(value)) {
|
|
323
|
+
return value
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (value instanceof Uint8Array) {
|
|
327
|
+
return Buffer.from(value)
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return Buffer.from(value)
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function normalizeCookieText(value: ArrayBuffer | Uint8Array | Buffer | string | null): string {
|
|
334
|
+
if (typeof value === 'string') {
|
|
335
|
+
return value.trim()
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const bytes = normalizeCookieBytes(value)
|
|
339
|
+
return bytes ? bytes.toString('utf8').trim() : ''
|
|
340
|
+
}
|
package/src/types.test.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { describe, expect, test } from 'bun:test'
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
ApplicationHistoryItemSchema,
|
|
5
|
+
ApprovalListItemSchema,
|
|
5
6
|
CredentialsSchema,
|
|
6
7
|
DashboardSchema,
|
|
7
8
|
EventListItemSchema,
|
|
@@ -11,6 +12,9 @@ import {
|
|
|
11
12
|
NoticeDetailSchema,
|
|
12
13
|
NoticeListItemSchema,
|
|
13
14
|
PaginationSchema,
|
|
15
|
+
ReportCreateOptionsSchema,
|
|
16
|
+
ReportDetailSchema,
|
|
17
|
+
ReportListItemSchema,
|
|
14
18
|
RoomCardSchema,
|
|
15
19
|
TeamInfoSchema,
|
|
16
20
|
} from './types'
|
|
@@ -48,6 +52,7 @@ describe('schemas', () => {
|
|
|
48
52
|
createdAt: '2026-04-01',
|
|
49
53
|
content: '<p>내용</p>',
|
|
50
54
|
venue: '온라인(Webex)',
|
|
55
|
+
applicants: [],
|
|
51
56
|
}),
|
|
52
57
|
).toBeDefined()
|
|
53
58
|
|
|
@@ -153,6 +158,82 @@ describe('schemas', () => {
|
|
|
153
158
|
loggedInAt: '2026-04-09T00:00:00.000Z',
|
|
154
159
|
}),
|
|
155
160
|
).toBeDefined()
|
|
161
|
+
|
|
162
|
+
expect(
|
|
163
|
+
ReportListItemSchema.parse({
|
|
164
|
+
id: 1,
|
|
165
|
+
category: '멘토링',
|
|
166
|
+
title: 'AI 멘토링 보고서',
|
|
167
|
+
progressDate: '2026-04-10',
|
|
168
|
+
status: '승인완료',
|
|
169
|
+
author: '전수열',
|
|
170
|
+
createdAt: '2026-04-11',
|
|
171
|
+
acceptedTime: '2시간',
|
|
172
|
+
payAmount: '100000',
|
|
173
|
+
}),
|
|
174
|
+
).toBeDefined()
|
|
175
|
+
|
|
176
|
+
expect(
|
|
177
|
+
ReportDetailSchema.parse({
|
|
178
|
+
id: 1,
|
|
179
|
+
category: '멘토링',
|
|
180
|
+
title: 'AI 멘토링 보고서',
|
|
181
|
+
progressDate: '2026-04-10',
|
|
182
|
+
status: '승인완료',
|
|
183
|
+
author: '전수열',
|
|
184
|
+
createdAt: '2026-04-11',
|
|
185
|
+
acceptedTime: '2시간',
|
|
186
|
+
payAmount: '100000',
|
|
187
|
+
content: '멘토링 진행 내용',
|
|
188
|
+
subject: 'AI 기술 멘토링',
|
|
189
|
+
menteeRegion: 'S',
|
|
190
|
+
reportType: 'MRC010',
|
|
191
|
+
teamNames: '오픈소마',
|
|
192
|
+
venue: '스페이스 A1',
|
|
193
|
+
attendanceCount: 4,
|
|
194
|
+
attendanceNames: '김개발, 박코딩, 이알고, 최리즘',
|
|
195
|
+
progressStartTime: '14:00',
|
|
196
|
+
progressEndTime: '16:00',
|
|
197
|
+
exceptStartTime: '',
|
|
198
|
+
exceptEndTime: '',
|
|
199
|
+
exceptReason: '',
|
|
200
|
+
mentorOpinion: '우수',
|
|
201
|
+
nonAttendanceNames: '',
|
|
202
|
+
etc: '',
|
|
203
|
+
files: [],
|
|
204
|
+
}),
|
|
205
|
+
).toBeDefined()
|
|
206
|
+
|
|
207
|
+
expect(
|
|
208
|
+
ApprovalListItemSchema.parse({
|
|
209
|
+
id: 1,
|
|
210
|
+
category: '멘토링',
|
|
211
|
+
title: 'AI 멘토링 보고서',
|
|
212
|
+
progressDate: '2026-04-10',
|
|
213
|
+
status: '승인완료',
|
|
214
|
+
author: '전수열',
|
|
215
|
+
createdAt: '2026-04-11',
|
|
216
|
+
acceptedTime: '2시간',
|
|
217
|
+
travelExpense: '50000',
|
|
218
|
+
mentoringAllowance: '100000',
|
|
219
|
+
}),
|
|
220
|
+
).toBeDefined()
|
|
221
|
+
|
|
222
|
+
expect(
|
|
223
|
+
ReportCreateOptionsSchema.parse({
|
|
224
|
+
menteeRegion: 'S',
|
|
225
|
+
reportType: 'MRC010',
|
|
226
|
+
progressDate: '2026-04-10',
|
|
227
|
+
venue: '스페이스 A1',
|
|
228
|
+
attendanceCount: 4,
|
|
229
|
+
attendanceNames: '김개발, 박코딩, 이알고, 최리즘',
|
|
230
|
+
progressStartTime: '14:00',
|
|
231
|
+
progressEndTime: '16:00',
|
|
232
|
+
subject: 'AI 멘토링 진행 보고',
|
|
233
|
+
content:
|
|
234
|
+
'이번 멘토링에서는 AI 기술의 기초 개념과 실제 적용 사례에 대해 다루었습니다. 참가자들은 머신러닝의 기본 원리와 딥러닝의 구조에 대해 학습하고, 실습을 통해 모델을 구현해보았습니다.',
|
|
235
|
+
}),
|
|
236
|
+
).toBeDefined()
|
|
156
237
|
})
|
|
157
238
|
|
|
158
239
|
test('reject invalid values', () => {
|
|
@@ -170,5 +251,21 @@ describe('schemas', () => {
|
|
|
170
251
|
expect(() => ApplicationHistoryItemSchema.parse({ id: 1, status: '신청완료' })).toThrow()
|
|
171
252
|
expect(() => PaginationSchema.parse({ total: '23', currentPage: 2, totalPages: 3 })).toThrow()
|
|
172
253
|
expect(() => CredentialsSchema.parse({ sessionCookie: 'cookie' })).toThrow()
|
|
254
|
+
expect(() => ReportListItemSchema.parse({ id: 1, category: '멘토링' })).toThrow()
|
|
255
|
+
expect(() => ReportDetailSchema.parse({ id: 1, category: '멘토링', title: '보고서' })).toThrow()
|
|
256
|
+
expect(() =>
|
|
257
|
+
ReportCreateOptionsSchema.parse({
|
|
258
|
+
menteeRegion: 'S',
|
|
259
|
+
reportType: 'MRC010',
|
|
260
|
+
progressDate: '2026-04-10',
|
|
261
|
+
venue: '스페이스 A1',
|
|
262
|
+
attendanceCount: 4,
|
|
263
|
+
attendanceNames: '김개발',
|
|
264
|
+
progressStartTime: '14:00',
|
|
265
|
+
progressEndTime: '16:00',
|
|
266
|
+
subject: '짧음',
|
|
267
|
+
content: '짧은 내용',
|
|
268
|
+
}),
|
|
269
|
+
).toThrow()
|
|
173
270
|
})
|
|
174
271
|
})
|
package/src/types.ts
CHANGED
|
@@ -34,9 +34,18 @@ export const MentoringListItemSchema = z.object({
|
|
|
34
34
|
})
|
|
35
35
|
export type MentoringListItem = z.infer<typeof MentoringListItemSchema>
|
|
36
36
|
|
|
37
|
+
export const MentoringApplicantSchema = z.object({
|
|
38
|
+
name: z.string(),
|
|
39
|
+
appliedAt: z.string(),
|
|
40
|
+
cancelledAt: z.string(),
|
|
41
|
+
status: z.string(),
|
|
42
|
+
})
|
|
43
|
+
export type MentoringApplicant = z.infer<typeof MentoringApplicantSchema>
|
|
44
|
+
|
|
37
45
|
export const MentoringDetailSchema = MentoringListItemSchema.extend({
|
|
38
46
|
content: z.string(),
|
|
39
47
|
venue: z.string(),
|
|
48
|
+
applicants: z.array(MentoringApplicantSchema),
|
|
40
49
|
})
|
|
41
50
|
export type MentoringDetail = z.infer<typeof MentoringDetailSchema>
|
|
42
51
|
|
|
@@ -135,6 +144,81 @@ export const CredentialsSchema = z.object({
|
|
|
135
144
|
cookies: z.string().optional(),
|
|
136
145
|
csrfToken: z.string(),
|
|
137
146
|
username: z.string().optional(),
|
|
147
|
+
password: z.string().optional(),
|
|
138
148
|
loggedInAt: z.string().optional(),
|
|
139
149
|
})
|
|
140
150
|
export type Credentials = z.infer<typeof CredentialsSchema>
|
|
151
|
+
|
|
152
|
+
export const ReportListItemSchema = z.object({
|
|
153
|
+
id: z.number(),
|
|
154
|
+
category: z.string(),
|
|
155
|
+
title: z.string(),
|
|
156
|
+
progressDate: z.string(),
|
|
157
|
+
status: z.string(),
|
|
158
|
+
author: z.string(),
|
|
159
|
+
createdAt: z.string(),
|
|
160
|
+
acceptedTime: z.string(),
|
|
161
|
+
payAmount: z.string(),
|
|
162
|
+
})
|
|
163
|
+
export type ReportListItem = z.infer<typeof ReportListItemSchema>
|
|
164
|
+
|
|
165
|
+
export const ReportDetailSchema = ReportListItemSchema.extend({
|
|
166
|
+
content: z.string(),
|
|
167
|
+
subject: z.string(),
|
|
168
|
+
menteeRegion: z.string(),
|
|
169
|
+
reportType: z.string(),
|
|
170
|
+
teamNames: z.string(),
|
|
171
|
+
venue: z.string(),
|
|
172
|
+
attendanceCount: z.number(),
|
|
173
|
+
attendanceNames: z.string(),
|
|
174
|
+
progressStartTime: z.string(),
|
|
175
|
+
progressEndTime: z.string(),
|
|
176
|
+
exceptStartTime: z.string(),
|
|
177
|
+
exceptEndTime: z.string(),
|
|
178
|
+
exceptReason: z.string(),
|
|
179
|
+
mentorOpinion: z.string(),
|
|
180
|
+
nonAttendanceNames: z.string(),
|
|
181
|
+
etc: z.string(),
|
|
182
|
+
files: z.array(z.string()),
|
|
183
|
+
})
|
|
184
|
+
export type ReportDetail = z.infer<typeof ReportDetailSchema>
|
|
185
|
+
|
|
186
|
+
export const ApprovalListItemSchema = z.object({
|
|
187
|
+
id: z.number(),
|
|
188
|
+
category: z.string(),
|
|
189
|
+
title: z.string(),
|
|
190
|
+
progressDate: z.string(),
|
|
191
|
+
status: z.string(),
|
|
192
|
+
author: z.string(),
|
|
193
|
+
createdAt: z.string(),
|
|
194
|
+
acceptedTime: z.string(),
|
|
195
|
+
travelExpense: z.string(),
|
|
196
|
+
mentoringAllowance: z.string(),
|
|
197
|
+
})
|
|
198
|
+
export type ApprovalListItem = z.infer<typeof ApprovalListItemSchema>
|
|
199
|
+
|
|
200
|
+
export const ReportCreateOptionsSchema = z.object({
|
|
201
|
+
menteeRegion: z.enum(['S', 'B']),
|
|
202
|
+
reportType: z.enum(['MRC010', 'MRC020']),
|
|
203
|
+
progressDate: z.string(),
|
|
204
|
+
teamNames: z.string().optional(),
|
|
205
|
+
venue: z.string(),
|
|
206
|
+
attendanceCount: z.number(),
|
|
207
|
+
attendanceNames: z.string(),
|
|
208
|
+
progressStartTime: z.string(),
|
|
209
|
+
progressEndTime: z.string(),
|
|
210
|
+
exceptStartTime: z.string().optional(),
|
|
211
|
+
exceptEndTime: z.string().optional(),
|
|
212
|
+
exceptReason: z.string().optional(),
|
|
213
|
+
subject: z.string().min(10),
|
|
214
|
+
content: z.string().min(100),
|
|
215
|
+
mentorOpinion: z.string().optional(),
|
|
216
|
+
nonAttendanceNames: z.string().optional(),
|
|
217
|
+
etc: z.string().optional(),
|
|
218
|
+
})
|
|
219
|
+
export type ReportCreateOptions = z.infer<typeof ReportCreateOptionsSchema>
|
|
220
|
+
|
|
221
|
+
export const ReportUpdateOptionsSchema = ReportCreateOptionsSchema.partial().extend({
|
|
222
|
+
id: z.number(),
|
|
223
|
+
})
|
|
224
|
+
export type ReportUpdateOptions = z.infer<typeof ReportUpdateOptionsSchema>
|