Skip to content
This repository has been archived by the owner on Nov 20, 2023. It is now read-only.

Commit

Permalink
Fixed getSettingsAttributes2() and Add updateSettingsAttributes2() an…
Browse files Browse the repository at this point in the history
…d negotiateE2EEPublicKey()
  • Loading branch information
WEDeach committed Jul 6, 2021
1 parent 77a569c commit 016f5ac
Show file tree
Hide file tree
Showing 5 changed files with 231 additions and 34 deletions.
2 changes: 1 addition & 1 deletion CHRLINE/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def sendLiff(self, to, messages, tryConsent=True):
'X-Requested-With': 'jp.naver.line.android'
}
liff_headers["authorization"] = 'Bearer %s'%(token)
if type(messages) == "list":
if type(messages) == list:
messages = {"messages":messages}
else:
messages = {"messages":[messages]}
Expand Down
53 changes: 34 additions & 19 deletions CHRLINE/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ def readContainerStruct(self, data, get_data_len=False, stopWithFirst=False):
nextPos = 0
dataType = data[0]
id = data[2]
#print(f"{id} -> {dataType}")
if data[0] == 2:
a = data[3]
if a == 1:
Expand All @@ -377,11 +378,11 @@ def readContainerStruct(self, data, get_data_len=False, stopWithFirst=False):
_data[id] = a
nextPos = 11
elif data[0] == 8:
a = int.from_bytes(data[3:7], "big")
a, = struct.unpack('!i', data[3:7])
_data[id] = a
nextPos = 7
elif data[0] == 10:
a = int.from_bytes(data[4:11], "big")
a, = struct.unpack('!q', data[3:11])
_data[id] = a
nextPos = 11
elif data[0] == 11:
Expand All @@ -407,22 +408,31 @@ def readContainerStruct(self, data, get_data_len=False, stopWithFirst=False):
elif data[0] == 13:
# dict
# 0D 00 24 0B 0B 00 00 00 02 00 00 00 07
# what is 24?
a = data[4] # value type? todo it?
b = data[8] # count
c = 12
kt = data[3] # key type
a = data[4] # value type
b, = struct.unpack('!i', data[5:9]) # count
c = 9
_d = {}
if b != 0:
#print(f"ktype: {kt}")
#print(f"kvalue: {a}")
for d in range(b):
e = data[c] # key len
f = c + e
if data[3] == 8:
f = c + 1
g = data[c + 4]
if True:
__key = self.readContainerStruct(bytes([kt, 0, 0]) + data[c:], get_data_len=True, stopWithFirst=True)
_key = __key[0][0]
vp = c + __key[1] - 3 # value pos
__value = self.readContainerStruct(bytes([a, 0, 0]) + data[vp:], get_data_len=True, stopWithFirst=True)
_value = __value[0][0]
c = vp + __value[1] - 3
# old code...
elif kt == 8:
# f = c + 1
# g = data[c + 4]
_key = data[c]
h = f + 4 + g
_value = data[f + 4:h].decode()
c = h # ??
_value = self.readContainerStruct(bytes([a, 0, 0]) + data[f + 1:])[0]
# h = f + 4 + g
# _value = data[f + 4:h].decode()
c += 5
else:
g = int.from_bytes(data[f + 1:f + 5], "big") # value len
_key = data[c + 1:f + 1].decode()
Expand All @@ -448,8 +458,9 @@ def readContainerStruct(self, data, get_data_len=False, stopWithFirst=False):
_d[_key] = _value
_data[id] = _d
nextPos = c
if a in [10, 11]:
nextPos -= 3
# old code...
# if a in [10, 11]:
# nextPos -= 3
else:
nextPos = 9
_data[id] = {}
Expand All @@ -460,8 +471,12 @@ def readContainerStruct(self, data, get_data_len=False, stopWithFirst=False):
nextPos = 8
if count != 0:
for i in range(count):
a = int.from_bytes(data[nextPos:nextPos + 4], "big")
b = data[nextPos + 4:nextPos + 4 + a].decode()
if type == 8:
a = 0
b = self.readContainerStruct(bytes([type, 0, 0]) + data[nextPos:])[0]
else:
a = int.from_bytes(data[nextPos:nextPos + 4], "big")
b = data[nextPos + 4:nextPos + 4 + a].decode()
_data[id].append(b)
nextPos += 4 + a
elif data[0] == 15:
Expand Down Expand Up @@ -494,7 +509,7 @@ def readContainerStruct(self, data, get_data_len=False, stopWithFirst=False):
nextPos = 8
elif data[0] != 0:
print(f"[readContainerStruct]不支援Type: {data[0]} => ID: {id}")
if nextPos > 0:
if nextPos > 0 and not stopWithFirst:
data = data[nextPos:]
c = self.readContainerStruct(data, True)
if c[0]:
Expand Down
198 changes: 188 additions & 10 deletions CHRLINE/services/TalkService.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,17 +154,15 @@ def getContactsV2(self, mids):
sqrd += [0, 0]
return self.postPackDataAndGetUnpackRespData(self.LINE_NORMAL_ENDPOINT ,sqrd)['getContactsV2']

def findAndAddContactsByMid(self, mid):

def findAndAddContactsByMid(self, mid, reference='{"screen":"groupMemberList","spec":"native"}'):
sqrd = [128, 1, 0, 1, 0, 0, 0, 23, 102, 105, 110, 100, 65, 110, 100, 65, 100, 100, 67, 111, 110, 116, 97, 99, 116, 115, 66, 121, 77, 105, 100, 0, 0, 0, 0]
sqrd += [8, 0, 1, 0, 0, 0, 0]
sqrd += [11, 0, 2, 0, 0, 0, 33]
for value in mid:
sqrd.append(ord(value))
sqrd += [8, 0, 3, 0, 0, 0, 0]
#sqrd += [11, 0, 4, 0, 0, 0, 0] # reference
sqrd += [11, 0, 4] + self.getStringBytes(reference)
sqrd += [0]

return self.postPackDataAndGetUnpackRespData(self.LINE_NORMAL_ENDPOINT ,sqrd)['findAndAddContactsByMid']

def getGroup(self, mid):
Expand Down Expand Up @@ -193,7 +191,7 @@ def getGroupsV2(self, mids):
return self.postPackDataAndGetUnpackRespData(self.LINE_NORMAL_ENDPOINT ,sqrd)['getGroupsV2']

def getChats(self, mids, withMembers=True, withInvitees=True):
if type(mids) != 'list':
if type(mids) != list:
raise Exception("[getChats] mids must be a list")
sqrd = [128, 1, 0, 1, 0, 0, 0, 8, 103, 101, 116, 67, 104, 97, 116, 115, 0, 0, 0, 0]
sqrd += [12, 0, 1]
Expand Down Expand Up @@ -225,7 +223,7 @@ def getCompactGroup(self, mid):
return self.postPackDataAndGetUnpackRespData(self.LINE_NORMAL_ENDPOINT ,sqrd)

def deleteOtherFromChat(self, to, mid):
if type(mid) == 'list':
if type(mid) == list:
_lastReq = None
for _mid in mid:
print(f'[deleteOtherFromChat] The parameter \'mid\' should be str')
Expand Down Expand Up @@ -643,17 +641,191 @@ def getRepairElements(self):
sqrd += [0, 0]
return self.postPackDataAndGetUnpackRespData(self.LINE_NORMAL_ENDPOINT ,sqrd)['getRepairElements']

def getSettingsAttributes2(self, attributesToRetrieve):
if type(attributesToRetrieve) != 'list':
def getSettingsAttributes2(self, attributesToRetrieve: list):
"""
NOTIFICATION_ENABLE(0),
NOTIFICATION_MUTE_EXPIRATION(1),
NOTIFICATION_NEW_MESSAGE(2),
NOTIFICATION_GROUP_INVITATION(3),
NOTIFICATION_SHOW_MESSAGE(4),
NOTIFICATION_INCOMING_CALL(5),
NOTIFICATION_SOUND_MESSAGE(8),
NOTIFICATION_SOUND_GROUP(9),
NOTIFICATION_DISABLED_WITH_SUB(16),
NOTIFICATION_PAYMENT(17),
NOTIFICATION_MENTION(40),
NOTIFICATION_THUMBNAIL(45),
NOTIFICATION_BADGE_TALK_ONLY(65),
NOTIFICATION_REACTION(67),
PRIVACY_SYNC_CONTACTS(6),
PRIVACY_SEARCH_BY_PHONE_NUMBER(7),
PRIVACY_SEARCH_BY_USERID(13),
PRIVACY_SEARCH_BY_EMAIL(14),
PRIVACY_SHARE_PERSONAL_INFO_TO_FRIENDS(51),
PRIVACY_ALLOW_SECONDARY_DEVICE_LOGIN(21),
PRIVACY_PROFILE_IMAGE_POST_TO_MYHOME(23),
PRIVACY_PROFILE_MUSIC_POST_TO_MYHOME(35),
PRIVACY_PROFILE_HISTORY(57),
PRIVACY_STATUS_MESSAGE_HISTORY(54),
PRIVACY_ALLOW_FRIEND_REQUEST(30),
PRIVACY_RECV_MESSAGES_FROM_NOT_FRIEND(25),
PRIVACY_AGREE_USE_LINECOIN_TO_PAIDCALL(26),
PRIVACY_AGREE_USE_PAIDCALL(27),
PRIVACY_AGE_RESULT(60),
PRIVACY_AGE_RESULT_RECEIVED(61),
PRIVACY_ALLOW_FOLLOW(63),
PRIVACY_SHOW_FOLLOW_LIST(64),
CONTACT_MY_TICKET(10),
IDENTITY_PROVIDER(11),
IDENTITY_IDENTIFIER(12),
SNS_ACCOUNT(19),
PHONE_REGISTRATION(20),
PWLESS_PRIMARY_CREDENTIAL_REGISTRATION(31),
ALLOWED_TO_CONNECT_EAP_ACCOUNT(32),
PREFERENCE_LOCALE(15),
CUSTOM_MODE(22),
EMAIL_CONFIRMATION_STATUS(24),
ACCOUNT_MIGRATION_PINCODE(28),
ENFORCED_INPUT_ACCOUNT_MIGRATION_PINCODE(29),
SECURITY_CENTER_SETTINGS(18),
E2EE_ENABLE(33),
HITOKOTO_BACKUP_REQUESTED(34),
CONTACT_ALLOW_FOLLOWING(36),
PRIVACY_ALLOW_NEARBY(37),
AGREEMENT_NEARBY(38),
AGREEMENT_SQUARE(39),
ALLOW_UNREGISTRATION_SECONDARY_DEVICE(41),
AGREEMENT_BOT_USE(42),
AGREEMENT_SHAKE_FUNCTION(43),
AGREEMENT_MOBILE_CONTACT_NAME(44),
AGREEMENT_SOUND_TO_TEXT(46),
AGREEMENT_PRIVACY_POLICY_VERSION(47),
AGREEMENT_AD_BY_WEB_ACCESS(48),
AGREEMENT_PHONE_NUMBER_MATCHING(49),
AGREEMENT_COMMUNICATION_INFO(50),
AGREEMENT_THINGS_WIRELESS_COMMUNICATION(52),
AGREEMENT_GDPR(53),
AGREEMENT_PROVIDE_LOCATION(55),
AGREEMENT_BEACON(56),
AGREEMENT_CONTENTS_SUGGEST(58),
AGREEMENT_CONTENTS_SUGGEST_DATA_COLLECTION(59),
AGREEMENT_OCR_IMAGE_COLLECTION(62),
AGREEMENT_ICNA(66),
AGREEMENT_MID(68),
HOME_NOTIFICATION_NEW_FRIEND(69),
HOME_NOTIFICATION_FAVORITE_FRIEND_UPDATE(70),
HOME_NOTIFICATION_GROUP_MEMBER_UPDATE(71),
HOME_NOTIFICATION_BIRTHDAY(72),
AGREEMENT_LINE_OUT_USE(73),
AGREEMENT_LINE_OUT_PROVIDE_INFO(74);
NOTIFICATION_ENABLE(0),
NOTIFICATION_MUTE_EXPIRATION(1),
NOTIFICATION_NEW_MESSAGE(2),
NOTIFICATION_GROUP_INVITATION(3),
NOTIFICATION_SHOW_MESSAGE(4),
NOTIFICATION_INCOMING_CALL(5),
NOTIFICATION_SOUND_MESSAGE(8),
NOTIFICATION_SOUND_GROUP(9),
NOTIFICATION_DISABLED_WITH_SUB(16),
NOTIFICATION_PAYMENT(17),
NOTIFICATION_MENTION(40),
NOTIFICATION_THUMBNAIL(45),
NOTIFICATION_BADGE_TALK_ONLY(65),
NOTIFICATION_REACTION(67),
PRIVACY_SYNC_CONTACTS(6),
PRIVACY_SEARCH_BY_PHONE_NUMBER(7),
PRIVACY_SEARCH_BY_USERID(13),
PRIVACY_SEARCH_BY_EMAIL(14),
PRIVACY_SHARE_PERSONAL_INFO_TO_FRIENDS(51),
PRIVACY_ALLOW_SECONDARY_DEVICE_LOGIN(21),
PRIVACY_PROFILE_IMAGE_POST_TO_MYHOME(23),
PRIVACY_PROFILE_MUSIC_POST_TO_MYHOME(35),
PRIVACY_PROFILE_HISTORY(57),
PRIVACY_STATUS_MESSAGE_HISTORY(54),
PRIVACY_ALLOW_FRIEND_REQUEST(30),
PRIVACY_RECV_MESSAGES_FROM_NOT_FRIEND(25),
PRIVACY_AGREE_USE_LINECOIN_TO_PAIDCALL(26),
PRIVACY_AGREE_USE_PAIDCALL(27),
PRIVACY_AGE_RESULT(60),
PRIVACY_AGE_RESULT_RECEIVED(61),
PRIVACY_ALLOW_FOLLOW(63),
PRIVACY_SHOW_FOLLOW_LIST(64),
CONTACT_MY_TICKET(10),
IDENTITY_PROVIDER(11),
IDENTITY_IDENTIFIER(12),
SNS_ACCOUNT(19),
PHONE_REGISTRATION(20),
PWLESS_PRIMARY_CREDENTIAL_REGISTRATION(31),
ALLOWED_TO_CONNECT_EAP_ACCOUNT(32),
PREFERENCE_LOCALE(15),
CUSTOM_MODE(22),
EMAIL_CONFIRMATION_STATUS(24),
ACCOUNT_MIGRATION_PINCODE(28),
ENFORCED_INPUT_ACCOUNT_MIGRATION_PINCODE(29),
SECURITY_CENTER_SETTINGS(18),
E2EE_ENABLE(33),
HITOKOTO_BACKUP_REQUESTED(34),
CONTACT_ALLOW_FOLLOWING(36),
PRIVACY_ALLOW_NEARBY(37),
AGREEMENT_NEARBY(38),
AGREEMENT_SQUARE(39),
ALLOW_UNREGISTRATION_SECONDARY_DEVICE(41),
AGREEMENT_BOT_USE(42),
AGREEMENT_SHAKE_FUNCTION(43),
AGREEMENT_MOBILE_CONTACT_NAME(44),
AGREEMENT_SOUND_TO_TEXT(46),
AGREEMENT_PRIVACY_POLICY_VERSION(47),
AGREEMENT_AD_BY_WEB_ACCESS(48),
AGREEMENT_PHONE_NUMBER_MATCHING(49),
AGREEMENT_COMMUNICATION_INFO(50),
AGREEMENT_THINGS_WIRELESS_COMMUNICATION(52),
AGREEMENT_GDPR(53),
AGREEMENT_PROVIDE_LOCATION(55),
AGREEMENT_BEACON(56),
AGREEMENT_CONTENTS_SUGGEST(58),
AGREEMENT_CONTENTS_SUGGEST_DATA_COLLECTION(59),
AGREEMENT_OCR_IMAGE_COLLECTION(62),
AGREEMENT_ICNA(66),
AGREEMENT_MID(68),
HOME_NOTIFICATION_NEW_FRIEND(69),
HOME_NOTIFICATION_FAVORITE_FRIEND_UPDATE(70),
HOME_NOTIFICATION_GROUP_MEMBER_UPDATE(71),
HOME_NOTIFICATION_BIRTHDAY(72),
AGREEMENT_LINE_OUT_USE(73),
AGREEMENT_LINE_OUT_PROVIDE_INFO(74);
"""
if type(attributesToRetrieve) != list:
attributesToRetrieve = [attributesToRetrieve]
print('[attributesToRetrieve] plz using LIST')
sqrd = [128, 1, 0, 1] + self.getStringBytes('getSettingsAttributes2') + [0, 0, 0, 0]
sqrd += [14, 0, 2, 11, 0, 0, 0, len(attributesToRetrieve)]
sqrd += [14, 0, 2, 8, 0, 0, 0, len(attributesToRetrieve)]
for value in attributesToRetrieve:
sqrd += self.getStringBytes(value)
sqrd += self.getIntBytes(value)
sqrd += [0, 0]
return self.postPackDataAndGetUnpackRespData(self.LINE_NORMAL_ENDPOINT ,sqrd)['getSettingsAttributes2']

def updateSettingsAttributes2(self, settings: dict, attributesToUpdate: list):
if type(attributesToUpdate) != list:
attributesToRetrieve = [attributesToUpdate]
print('[attributesToRetrieve] plz using LIST')
sqrd = [128, 1, 0, 1] + self.getStringBytes('updateSettingsAttributes2') + [0, 0, 0, 0]
sqrd += [8, 0, 1] + self.getIntBytes(0) #reqSeq
sqrd += [12, 0, 3]
for sk, sv in settings.items():
svt = type(sv)
if svt == bool:
sqrd += [2, 0, sk, int(sv)]
elif svt == int:
sqrd += [10, 0, sk] + self.getIntBytes(sv, 8)
else:
print(f"[updateSettingsAttributes2] not support type {svt} (id: {sk})")
sqrd += [0]
sqrd += [14, 0, 4, 8, 0, 0, 0, len(attributesToUpdate)]
for value in attributesToUpdate:
sqrd += self.getIntBytes(value)
sqrd += [0, 0]
return self.postPackDataAndGetUnpackRespData(self.LINE_NORMAL_ENDPOINT ,sqrd)['updateSettingsAttributes2']

def rejectChatInvitation(self, chatMid):
sqrd = [128, 1, 0, 1] + self.getStringBytes('rejectChatInvitation') + [0, 0, 0, 0]
sqrd += [12, 0, 1]
Expand Down Expand Up @@ -683,4 +855,10 @@ def updateProfileAttribute(self, attr: int, value: str):
sqrd += [11, 0, 3] + self.getStringBytes(value)
sqrd += [0]
return self.postPackDataAndGetUnpackRespData(self.LINE_NORMAL_ENDPOINT ,sqrd)['updateProfileAttribute']

def negotiateE2EEPublicKey(self, mid: str):
sqrd = [128, 1, 0, 1] + self.getStringBytes('negotiateE2EEPublicKey') + [0, 0, 0, 0]
sqrd += [11, 0, 2] + self.getStringBytes(mid)
sqrd += [0]
return self.postPackDataAndGetUnpackRespData(self.LINE_NORMAL_ENDPOINT ,sqrd)['negotiateE2EEPublicKey']

2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,10 @@ If you want to write TMoreCompact, only need to sniff results and reverse engine
- sendEchoPush
- getRepairElements
- getSettingsAttributes2
- updateSettingsAttributes2
- rejectChatInvitation
- updateProfileAttribute
- negotiateE2EEPublicKey
- ShopService
- getProduct
- getProductsByAuthor
Expand Down
10 changes: 6 additions & 4 deletions examples/test_register.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def create_token(auth_key: str) -> str:


UPDATE_NAME = True
TURN_OFF_E2EE = False
DISPLAY_NAME = "yinmo"


Expand Down Expand Up @@ -106,11 +107,12 @@ def create_token(auth_key: str) -> str:
print(f"authKey: {authKey}")
print(f"authToken: {authToken}")

cl = CHRLINE(authToken, device="ANDROID") #login

if UPDATE_NAME:
cl = CHRLINE(authToken, device="ANDROID") #login
cl.updateProfileAttribute(2, DISPLAY_NAME) #update display name

# update email step:
# openAuthSession -> getAuthRSAKey and encrypt -> setIdentifier -> confirmIdentifier

if TURN_OFF_E2EE:
sett = cl.getSettingsAttributes2([33])
sett[61] = False
cl.updateSettingsAttributes2(sett, [33])

0 comments on commit 016f5ac

Please sign in to comment.