mirror of
https://github.com/faroukbmiled/RyukGram.git
synced 2026-04-22 04:06:10 +02:00
feat: Unlock password-locked reels (auto unlock and view passowrd)
This commit is contained in:
@@ -51,6 +51,7 @@ A feature-rich iOS tweak for Instagram, forked from [SCInsta](https://github.com
|
||||
- Always show progress scrubber
|
||||
- Disable auto-unmuting reels (properly blocks mute switch, volume buttons, and announcer broadcasts) **\***
|
||||
- Confirm reel refresh
|
||||
- Unlock password-locked reels **\***
|
||||
- Hide reels header
|
||||
- Hide reels blend button
|
||||
- Disable scrolling reels
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
#import "../../InstagramHeaders.h"
|
||||
#import "../../Utils.h"
|
||||
#import <objc/runtime.h>
|
||||
#import <objc/message.h>
|
||||
|
||||
// Password-locked reels use IGMediaOverlayProfileWithPasswordView as a blur overlay.
|
||||
// The password is stored in the _asnwer ivar (IG typo). We read it at runtime,
|
||||
// then provide buttons to auto-fill + submit or reveal + copy the password.
|
||||
|
||||
#define SCI_PW_BTN_TAG 1342
|
||||
|
||||
static NSString * _Nullable sciGetPassword(id overlayView) {
|
||||
Class cls = [overlayView class];
|
||||
while (cls && cls != [UIView class]) {
|
||||
unsigned int count = 0;
|
||||
Ivar *ivars = class_copyIvarList(cls, &count);
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
const char *name = ivar_getName(ivars[i]);
|
||||
if (name && strcmp(name, "_asnwer") == 0) {
|
||||
id value = object_getIvar(overlayView, ivars[i]);
|
||||
free(ivars);
|
||||
if ([value isKindOfClass:[NSString class]] && [(NSString *)value length] > 0)
|
||||
return (NSString *)value;
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
if (ivars) free(ivars);
|
||||
cls = class_getSuperclass(cls);
|
||||
}
|
||||
|
||||
// Fallback: scan for any password-related string ivar
|
||||
cls = [overlayView class];
|
||||
while (cls && cls != [UIView class]) {
|
||||
unsigned int count = 0;
|
||||
Ivar *ivars = class_copyIvarList(cls, &count);
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
const char *type = ivar_getTypeEncoding(ivars[i]);
|
||||
if (!type || type[0] != '@') continue;
|
||||
@try {
|
||||
id value = object_getIvar(overlayView, ivars[i]);
|
||||
if (![value isKindOfClass:[NSString class]] || [(NSString *)value length] == 0) continue;
|
||||
const char *name = ivar_getName(ivars[i]);
|
||||
if (!name) continue;
|
||||
NSString *lower = [[NSString stringWithUTF8String:name] lowercaseString];
|
||||
if ([lower containsString:@"answer"] || [lower containsString:@"asnwer"] ||
|
||||
[lower containsString:@"password"] || [lower containsString:@"secret"]) {
|
||||
free(ivars);
|
||||
return (NSString *)value;
|
||||
}
|
||||
} @catch(id e) {}
|
||||
}
|
||||
if (ivars) free(ivars);
|
||||
cls = class_getSuperclass(cls);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
static UITextField * _Nullable sciFindTextField(UIView *root) {
|
||||
NSMutableArray *stack = [NSMutableArray arrayWithObject:root];
|
||||
while (stack.count > 0) {
|
||||
UIView *v = stack.lastObject;
|
||||
[stack removeLastObject];
|
||||
if ([v isKindOfClass:[UITextField class]]) return (UITextField *)v;
|
||||
for (UIView *sub in v.subviews) [stack addObject:sub];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
static UIView * _Nullable sciFindSubmitButton(UIView *root) {
|
||||
NSMutableArray *stack = [NSMutableArray arrayWithObject:root];
|
||||
while (stack.count > 0) {
|
||||
UIView *v = stack.lastObject;
|
||||
[stack removeLastObject];
|
||||
if ([NSStringFromClass([v class]) containsString:@"IGDSMediaTextButton"]) return v;
|
||||
for (UIView *sub in v.subviews) [stack addObject:sub];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
%hook IGMediaOverlayProfileWithPasswordView
|
||||
|
||||
- (void)didMoveToSuperview {
|
||||
%orig;
|
||||
if (!self.superview) return;
|
||||
if (![SCIUtils getBoolPref:@"unlock_password_reels"]) return;
|
||||
[self sciAddButtons];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
%orig;
|
||||
if (![SCIUtils getBoolPref:@"unlock_password_reels"]) return;
|
||||
[self sciAddButtons];
|
||||
}
|
||||
|
||||
%new - (void)sciAddButtons {
|
||||
if ([self viewWithTag:SCI_PW_BTN_TAG]) return;
|
||||
|
||||
UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:18 weight:UIImageSymbolWeightBold];
|
||||
|
||||
UIButton *unlockBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
unlockBtn.tag = SCI_PW_BTN_TAG;
|
||||
[unlockBtn setImage:[UIImage systemImageNamed:@"lock.open.fill" withConfiguration:config] forState:UIControlStateNormal];
|
||||
unlockBtn.tintColor = [UIColor colorWithRed:1.0 green:0.85 blue:0.0 alpha:1.0];
|
||||
unlockBtn.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.5];
|
||||
unlockBtn.layer.cornerRadius = 20;
|
||||
unlockBtn.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[unlockBtn addTarget:self action:@selector(sciUnlockTapped) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self addSubview:unlockBtn];
|
||||
|
||||
UIButton *eyeBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
eyeBtn.tag = SCI_PW_BTN_TAG + 1;
|
||||
[eyeBtn setImage:[UIImage systemImageNamed:@"eye.fill" withConfiguration:config] forState:UIControlStateNormal];
|
||||
eyeBtn.tintColor = [UIColor whiteColor];
|
||||
eyeBtn.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.5];
|
||||
eyeBtn.layer.cornerRadius = 20;
|
||||
eyeBtn.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[eyeBtn addTarget:self action:@selector(sciShowPasswordTapped) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self addSubview:eyeBtn];
|
||||
|
||||
[NSLayoutConstraint activateConstraints:@[
|
||||
[unlockBtn.topAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.topAnchor constant:200],
|
||||
[unlockBtn.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-16],
|
||||
[unlockBtn.widthAnchor constraintEqualToConstant:40],
|
||||
[unlockBtn.heightAnchor constraintEqualToConstant:40],
|
||||
|
||||
[eyeBtn.topAnchor constraintEqualToAnchor:unlockBtn.bottomAnchor constant:12],
|
||||
[eyeBtn.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-16],
|
||||
[eyeBtn.widthAnchor constraintEqualToConstant:40],
|
||||
[eyeBtn.heightAnchor constraintEqualToConstant:40],
|
||||
]];
|
||||
}
|
||||
|
||||
%new - (void)sciUnlockTapped {
|
||||
UIImpactFeedbackGenerator *haptic = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleMedium];
|
||||
[haptic impactOccurred];
|
||||
|
||||
NSString *password = sciGetPassword(self);
|
||||
if (!password) {
|
||||
[SCIUtils showErrorHUDWithDescription:@"No password found"];
|
||||
return;
|
||||
}
|
||||
|
||||
UITextField *textField = sciFindTextField(self);
|
||||
if (!textField) {
|
||||
[SCIUtils showErrorHUDWithDescription:@"No text field found"];
|
||||
return;
|
||||
}
|
||||
|
||||
textField.text = password;
|
||||
[textField sendActionsForControlEvents:UIControlEventEditingChanged];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:UITextFieldTextDidChangeNotification object:textField];
|
||||
|
||||
if (textField.delegate) {
|
||||
if ([textField.delegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)])
|
||||
[textField.delegate textField:textField shouldChangeCharactersInRange:NSMakeRange(0, 0) replacementString:password];
|
||||
if ([textField.delegate respondsToSelector:@selector(textFieldDidChangeSelection:)])
|
||||
[textField.delegate textFieldDidChangeSelection:textField];
|
||||
}
|
||||
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
UIView *submitBtn = sciFindSubmitButton(self);
|
||||
if (submitBtn && [submitBtn isKindOfClass:[UIControl class]]) {
|
||||
[(UIControl *)submitBtn setHidden:NO];
|
||||
[(UIControl *)submitBtn sendActionsForControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
%new - (void)sciShowPasswordTapped {
|
||||
UIImpactFeedbackGenerator *haptic = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight];
|
||||
[haptic impactOccurred];
|
||||
|
||||
NSString *password = sciGetPassword(self);
|
||||
if (!password) {
|
||||
[SCIUtils showErrorHUDWithDescription:@"No password found"];
|
||||
return;
|
||||
}
|
||||
|
||||
[[UIPasteboard generalPasteboard] setString:password];
|
||||
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Password"
|
||||
message:password
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Copied!" style:UIAlertActionStyleCancel handler:nil]];
|
||||
UIViewController *topVC = topMostController();
|
||||
if (topVC) [topVC presentViewController:alert animated:YES completion:nil];
|
||||
}
|
||||
|
||||
%end
|
||||
@@ -425,6 +425,12 @@
|
||||
@interface IGSundialViewerNavigationBarOld : UIView
|
||||
@end
|
||||
|
||||
@interface IGMediaOverlayProfileWithPasswordView : UIView
|
||||
- (void)sciAddButtons;
|
||||
- (void)sciUnlockTapped;
|
||||
- (void)sciShowPasswordTapped;
|
||||
@end
|
||||
|
||||
@interface IGUFIInteractionCountsView : UIView
|
||||
@end
|
||||
|
||||
|
||||
@@ -85,6 +85,7 @@
|
||||
[SCISetting switchCellWithTitle:@"Always show progress scrubber" subtitle:@"Forces the progress bar to appear on every reel" defaultsKey:@"reels_show_scrubber"],
|
||||
[SCISetting switchCellWithTitle:@"Disable auto-unmuting reels" subtitle:@"Prevents reels from unmuting when the volume/silent button is pressed" defaultsKey:@"disable_auto_unmuting_reels" requiresRestart:YES],
|
||||
[SCISetting switchCellWithTitle:@"Confirm reel refresh" subtitle:@"Shows an alert when you trigger a reels refresh" defaultsKey:@"refresh_reel_confirm"],
|
||||
[SCISetting switchCellWithTitle:@"Unlock password-locked reels" subtitle:@"Shows buttons to reveal and auto-fill the password on locked reels" defaultsKey:@"unlock_password_reels"],
|
||||
]
|
||||
},
|
||||
@{
|
||||
|
||||
+2
-1
@@ -46,7 +46,8 @@ BOOL dmVisualMsgsViewedButtonEnabled = false;
|
||||
@"disable_auto_unmuting_reels": @(YES),
|
||||
@"doom_scrolling_reel_count": @(1),
|
||||
@"no_seen_visual": @(YES),
|
||||
@"send_audio_as_file": @(YES)
|
||||
@"send_audio_as_file": @(YES),
|
||||
@"unlock_password_reels": @(YES)
|
||||
};
|
||||
[[NSUserDefaults standardUserDefaults] registerDefaults:sciDefaults];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user