Skip to content

Commit

Permalink
fix: #1109 support telegra.ph login
Browse files Browse the repository at this point in the history
  • Loading branch information
terwer committed Apr 2, 2024
1 parent ab25c51 commit 99c9b28
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 78 deletions.
149 changes: 82 additions & 67 deletions src/adaptors/api/telegraph/telegraphApiAdaptor.ts
Expand Up @@ -42,8 +42,25 @@ class TelegraphApiAdaptor extends BaseBlogApi {
public async getUsersBlogs(): Promise<UserBlog[]> {
const result: UserBlog[] = []

const contentType = "text/plain"
let xCorsHeaders: Record<any, any> = {}

// x-cors-headers
xCorsHeaders["origin"] = "https://telegra.ph"
xCorsHeaders["referer"] = "https://telegra.ph/"
xCorsHeaders["Content-Type"] = contentType

const headers = {
// for cors proxy
// siyuan proxy should ignore this header
"x-cors-headers": JSON.stringify(xCorsHeaders),
}
for (const [xkey, xvalue] of Object.entries(xCorsHeaders)) {
headers[xkey] = xvalue
}

let cookies: any
let checkJson = await this.telegraphFetch("/check", "page_id=0", "POST")
let checkJson = await this.telegraphFetch("/check", "page_id=0", "POST", headers, contentType)
this.logger.debug("checkJson =>", checkJson)

if (checkJson["cors-received-headers"]) {
Expand Down Expand Up @@ -75,18 +92,46 @@ class TelegraphApiAdaptor extends BaseBlogApi {
userblog.url = cfg.apiUrl
// 元数据映射
// @since 1.20.0
const newCookies = CookieUtils.addCookieArray(this.cfg?.corsCookieArray ?? [], cookies)
userblog.metadataMap = {
password: checkJson.save_hash,
corsCookieArray: newCookies,
const { isUpdated, cookieArray } = CookieUtils.addCookieArray(this.cfg?.corsCookieArray ?? [], cookies)
// save_hash 必须和 Cookie 的有效期同时有效
if (isUpdated) {
userblog.metadataMap = {
password: checkJson.save_hash,
corsCookieArray: cookieArray,
}
} else {
this.logger.warn("Cookie 还在有效期,可等待 Cookie 过期之后再进行操作", cookieArray)
}

result.push(userblog)
this.logger.debug("get telegraph cfg =>", result)

return result
}

public async newPost(post: Post, _publish?: boolean): Promise<string> {
let xCorsHeaders: Record<any, any> = {}

// x-cors-headers
const tphUuidObj = CookieUtils.getCookieObject(this.cfg.corsCookieArray, this.TPH_UUID_KEY)
if (StrUtil.isEmptyString(tphUuidObj[this.TPH_UUID_KEY])) {
throw new Error("Cookie 获取失败,无法新建文章")
}

const requestCookie = `${this.TPH_UUID_KEY}=${tphUuidObj[this.TPH_UUID_KEY]}`
xCorsHeaders["Cookie"] = requestCookie
xCorsHeaders["origin"] = "https://telegra.ph"
xCorsHeaders["referer"] = "https://telegra.ph/"

const headers = {
// for cors proxy
// siyuan proxy should ignore this header
"x-cors-headers": JSON.stringify(xCorsHeaders),
}
for (const [xkey, xvalue] of Object.entries(xCorsHeaders)) {
headers[xkey] = xvalue
}

// 这里不用这个,因为 telegraph 必须强制代理
// const { FormData, Blob } = FormDataUtils.getFormData(this.appInstance)

Expand All @@ -99,7 +144,7 @@ class TelegraphApiAdaptor extends BaseBlogApi {
formData.append("save_hash", this.cfg.password)
formData.append("page_id", "0")

const res = await this.telegraphFormFetch("/save", formData)
const res = await this.telegraphFormFetch("/save", formData, headers)
if (res.error) {
throw new Error(
"telegra.ph 发布错误,注意:切换设备(包括从PC到浏览器环境)需要重新验证,并且获取新token。详细错误 =>" +
Expand All @@ -109,6 +154,7 @@ class TelegraphApiAdaptor extends BaseBlogApi {
this.logger.debug("telegraph newPost resJson =>", res)

const postMeta = {
update_cookie: requestCookie,
page_id: res.page_id,
path: res.path,
}
Expand All @@ -117,10 +163,31 @@ class TelegraphApiAdaptor extends BaseBlogApi {
}

public async editPost(postid: string, post: Post, publish?: boolean): Promise<boolean> {
const { FormData, Blob } = FormDataUtils.getFormData(this.appInstance)

const postMeta = JsonUtil.safeParse<any>(postid, {})

let xCorsHeaders: Record<any, any> = {}

// x-cors-headers
if (StrUtil.isEmptyString(postMeta.update_cookie)) {
throw new Error("Cookie 获取失败,无法更新文章")
}

xCorsHeaders["Cookie"] = postMeta.update_cookie
xCorsHeaders["origin"] = "https://telegra.ph"
xCorsHeaders["referer"] = "https://telegra.ph/"

const headers = {
// for cors proxy
// siyuan proxy should ignore this header
"x-cors-headers": JSON.stringify(xCorsHeaders),
}
for (const [xkey, xvalue] of Object.entries(xCorsHeaders)) {
headers[xkey] = xvalue
}

// 这里不用这个,因为 telegraph 必须强制代理
// const { FormData, Blob } = FormDataUtils.getFormData(this.appInstance)

const formData = new FormData()
const content = md(post.description)
const blobData = new Blob([JSON.stringify(content)], { type: "text/plain" })
Expand All @@ -130,7 +197,7 @@ class TelegraphApiAdaptor extends BaseBlogApi {
formData.append("save_hash", this.cfg.password)
formData.append("page_id", postMeta.page_id)

const res = await this.telegraphFormFetch("/save", formData)
const res = await this.telegraphFormFetch("/save", formData, headers)
if (res.error) {
throw new Error(
"telegra.ph 更新失败,注意:切换设备(包括从PC到浏览器环境)需要重新验证,并且获取新token。详细错误 =>" +
Expand Down Expand Up @@ -174,42 +241,9 @@ class TelegraphApiAdaptor extends BaseBlogApi {
url: string,
params?: any,
method: "GET" | "POST" | "PUT" | "DELETE" = "GET",
header: Record<any, any> = {}
headers: Record<any, any> = {},
contentType: string = "application/json"
) {
const contentType = "text/plain"
// const tphUuidObj = CookieUtils.getCookieObject(this.cfg.corsCookieArray, this.TPH_UUID_KEY)
// if (!StrUtil.isEmptyString(tphUuidObj[this.TPH_UUID_KEY])) {
// header["Cookie"] = `${this.TPH_UUID_KEY}=${tphUuidObj[this.TPH_UUID_KEY]}`
// }

// const headers = {
// "Content-Type": contentType,
// origin: "https://telegra.ph",
// referer: "https://telegra.ph/",
// ...header,
// }
let xCorsHeaders: Record<any, any> = {}

// header

// x-cors-headers
const tphUuidObj = CookieUtils.getCookieObject(this.cfg.corsCookieArray, this.TPH_UUID_KEY)
if (!StrUtil.isEmptyString(tphUuidObj[this.TPH_UUID_KEY])) {
xCorsHeaders["Cookie"] = `${this.TPH_UUID_KEY}=${tphUuidObj[this.TPH_UUID_KEY]}`
}
xCorsHeaders["origin"] = "https://telegra.ph"
xCorsHeaders["referer"] = "https://telegra.ph/"
xCorsHeaders["Content-Type"] = contentType

const headers = {
// for cors proxy
// siyuan proxy should ignore this header
"x-cors-headers": JSON.stringify(xCorsHeaders),
}
for (const [xkey, xvalue] of Object.entries(xCorsHeaders)) {
headers[xkey] = xvalue
}

const body = params

// 输出日志
Expand All @@ -219,7 +253,7 @@ class TelegraphApiAdaptor extends BaseBlogApi {
this.logger.debug("向 Telegraph 请求数据,headers =>", headers)
this.logger.debug("向 Telegraph 请求数据,body =>", body)

const resJson = await this.apiProxyFetch(apiUrl, [headers], body, method, contentType, false)
const resJson = await this.apiProxyFetch(apiUrl, [headers], body, method, contentType, true)
this.logger.debug("向 Telegraph 请求数据,resJson =>", resJson)

return resJson ?? null
Expand All @@ -230,29 +264,10 @@ class TelegraphApiAdaptor extends BaseBlogApi {
*
* @param url 请求地址
* @param formData 表单数据,默认为undefined,支持 ReadableStream、Blob | BufferSource | FormData | URLSearchParams | string。这里只需要 FormData
* @param headers
*/
private async telegraphFormFetch(url: string, formData: FormData) {
private async telegraphFormFetch(url: string, formData: FormData, headers: Record<any, any> = {}) {
const apiUrl = `${this.cfg.apiUrl}${url}`
let xCorsHeaders: Record<any, any> = {}

// header

// x-cors-headers
const tphUuidObj = CookieUtils.getCookieObject(this.cfg.corsCookieArray, this.TPH_UUID_KEY)
if (!StrUtil.isEmptyString(tphUuidObj[this.TPH_UUID_KEY])) {
xCorsHeaders["Cookie"] = `${this.TPH_UUID_KEY}=${tphUuidObj[this.TPH_UUID_KEY]}`
}
xCorsHeaders["origin"] = "https://telegra.ph"
xCorsHeaders["referer"] = "https://telegra.ph/"

const headers = {
// for cors proxy
// siyuan proxy should ignore this header
"x-cors-headers": JSON.stringify(xCorsHeaders),
}
for (const [xkey, xvalue] of Object.entries(xCorsHeaders)) {
headers[xkey] = xvalue
}

const options: RequestInit = {
method: "POST",
Expand All @@ -263,7 +278,7 @@ class TelegraphApiAdaptor extends BaseBlogApi {
this.logger.debug("向 Telegraph 发送表单数据,apiUrl =>", apiUrl)
this.logger.debug("向 Telegraph 发送表单数据,options =>", options)

const resJson = await this.apiProxyFormFetch(apiUrl, [headers], formData, false)
const resJson = await this.apiProxyFormFetch(apiUrl, [headers], formData, true)
if (resJson.error) {
throw new Error(
"telegra.ph 发布错误,注意:切换设备(包括从PC到浏览器环境)需要重新验证,并且获取新token。详细错误 =>" +
Expand Down
30 changes: 19 additions & 11 deletions src/utils/cookieUtils.ts
Expand Up @@ -39,30 +39,38 @@ class CookieUtils {
*
* @param originCookieArray
* @param newCookieArray
* @param isForce
*/
public static addCookieArray(originCookieArray: string[], newCookieArray: string[]) {
public static addCookieArray(originCookieArray: string[], newCookieArray: string[], isForce: boolean = false) {
let isUpdated = false
newCookieArray.forEach((newItem) => {
const [key] = newItem.split("=")
const newCookieObj = this.parseCookie(newItem)

// 检查是否存在相同 key 的 cookie,并比较有效期
const existingIndex = originCookieArray.findIndex((item) => item.startsWith(`${key}=`))
if (existingIndex !== -1) {
const existingCookie = this.parseCookie(originCookieArray[existingIndex])
// 若新 cookie 的有效期大于旧的,则更新
if (
!StrUtil.isEmptyString(newCookieObj.expires) &&
!StrUtil.isEmptyString(existingCookie.expires) &&
new Date(newCookieObj.expires).getTime() > new Date(existingCookie.expires).getTime()
) {
originCookieArray[existingIndex] = newItem
}
// const existingCookie = this.parseCookie(originCookieArray[existingIndex])
// // 若新 cookie 的有效期大于旧的,则更新
// if (
// (!StrUtil.isEmptyString(newCookieObj.expires) &&
// !StrUtil.isEmptyString(existingCookie.expires) &&
// new Date(newCookieObj.expires).getTime() > new Date(existingCookie.expires).getTime()) ||
// isForce
// ) {
// originCookieArray[existingIndex] = newItem
isUpdated = false
// }
} else {
originCookieArray.push(newItem)
isUpdated = true
}
})

return _.uniq(originCookieArray)
return {
isUpdated,
cookieArray: _.uniq(originCookieArray),
}
}

/**
Expand Down

0 comments on commit 99c9b28

Please sign in to comment.